]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavformat/libnut.c
frsh: Export information about the last RTP contract and VRES
[frescor/ffmpeg.git] / libavformat / libnut.c
1 /*
2  * NUT (de)muxing via libnut
3  * copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file libavformat/libnut.c
24  * NUT demuxing and muxing via libnut.
25  * @author Oded Shimon <ods15@ods15.dyndns.org>
26  */
27
28 #include "avformat.h"
29 #include "riff.h"
30 #include <libnut.h>
31
32 #define ID_STRING "nut/multimedia container"
33 #define ID_LENGTH (strlen(ID_STRING) + 1)
34
35 typedef struct {
36     nut_context_tt * nut;
37     nut_stream_header_tt * s;
38 } NUTContext;
39
40 static const AVCodecTag nut_tags[] = {
41     { CODEC_ID_MPEG4,  MKTAG('m', 'p', '4', 'v') },
42     { CODEC_ID_MP3,    MKTAG('m', 'p', '3', ' ') },
43     { CODEC_ID_VORBIS, MKTAG('v', 'r', 'b', 's') },
44     { 0, 0 },
45 };
46
47 #if CONFIG_LIBNUT_MUXER
48 static int av_write(void * h, size_t len, const uint8_t * buf) {
49     ByteIOContext * bc = h;
50     put_buffer(bc, buf, len);
51     //put_flush_packet(bc);
52     return len;
53 }
54
55 static int nut_write_header(AVFormatContext * avf) {
56     NUTContext * priv = avf->priv_data;
57     ByteIOContext * bc = avf->pb;
58     nut_muxer_opts_tt mopts = {
59         .output = {
60             .priv = bc,
61             .write = av_write,
62         },
63         .alloc = { av_malloc, av_realloc, av_free },
64         .write_index = 1,
65         .realtime_stream = 0,
66         .max_distance = 32768,
67         .fti = NULL,
68     };
69     nut_stream_header_tt * s;
70     int i;
71
72     priv->s = s = av_mallocz((avf->nb_streams + 1) * sizeof*s);
73
74     for (i = 0; i < avf->nb_streams; i++) {
75         AVCodecContext * codec = avf->streams[i]->codec;
76         int j;
77         int fourcc = 0;
78         int num, denom, ssize;
79
80         s[i].type = codec->codec_type == CODEC_TYPE_VIDEO ? NUT_VIDEO_CLASS : NUT_AUDIO_CLASS;
81
82         if (codec->codec_tag) fourcc = codec->codec_tag;
83         else fourcc = codec_get_tag(nut_tags, codec->codec_id);
84
85         if (!fourcc) {
86             if (codec->codec_type == CODEC_TYPE_VIDEO) fourcc = codec_get_tag(codec_bmp_tags, codec->codec_id);
87             if (codec->codec_type == CODEC_TYPE_AUDIO) fourcc = codec_get_tag(codec_wav_tags, codec->codec_id);
88         }
89
90         s[i].fourcc_len = 4;
91         s[i].fourcc = av_malloc(s[i].fourcc_len);
92         for (j = 0; j < s[i].fourcc_len; j++) s[i].fourcc[j] = (fourcc >> (j*8)) & 0xFF;
93
94         ff_parse_specific_params(codec, &num, &ssize, &denom);
95         av_set_pts_info(avf->streams[i], 60, denom, num);
96
97         s[i].time_base.num = denom;
98         s[i].time_base.den = num;
99
100         s[i].fixed_fps = 0;
101         s[i].decode_delay = codec->has_b_frames;
102         s[i].codec_specific_len = codec->extradata_size;
103         s[i].codec_specific = codec->extradata;
104
105         if (codec->codec_type == CODEC_TYPE_VIDEO) {
106             s[i].width = codec->width;
107             s[i].height = codec->height;
108             s[i].sample_width = 0;
109             s[i].sample_height = 0;
110             s[i].colorspace_type = 0;
111         } else {
112             s[i].samplerate_num = codec->sample_rate;
113             s[i].samplerate_denom = 1;
114             s[i].channel_count = codec->channels;
115         }
116     }
117
118     s[avf->nb_streams].type = -1;
119     priv->nut = nut_muxer_init(&mopts, s, NULL);
120
121     return 0;
122 }
123
124 static int nut_write_packet(AVFormatContext * avf, AVPacket * pkt) {
125     NUTContext * priv = avf->priv_data;
126     nut_packet_tt p;
127
128     p.len = pkt->size;
129     p.stream = pkt->stream_index;
130     p.pts = pkt->pts;
131     p.flags = pkt->flags & PKT_FLAG_KEY ? NUT_FLAG_KEY : 0;
132     p.next_pts = 0;
133
134     nut_write_frame_reorder(priv->nut, &p, pkt->data);
135
136     return 0;
137 }
138
139 static int nut_write_trailer(AVFormatContext * avf) {
140     ByteIOContext * bc = avf->pb;
141     NUTContext * priv = avf->priv_data;
142     int i;
143
144     nut_muxer_uninit_reorder(priv->nut);
145     put_flush_packet(bc);
146
147     for(i = 0; priv->s[i].type != -1; i++ ) av_freep(&priv->s[i].fourcc);
148     av_freep(&priv->s);
149
150     return 0;
151 }
152
153 AVOutputFormat libnut_muxer = {
154     "libnut",
155     "nut format",
156     "video/x-nut",
157     "nut",
158     sizeof(NUTContext),
159     CODEC_ID_VORBIS,
160     CODEC_ID_MPEG4,
161     nut_write_header,
162     nut_write_packet,
163     nut_write_trailer,
164     .flags = AVFMT_GLOBALHEADER,
165 };
166 #endif /* CONFIG_LIBNUT_MUXER */
167
168 static int nut_probe(AVProbeData *p) {
169     if (!memcmp(p->buf, ID_STRING, ID_LENGTH)) return AVPROBE_SCORE_MAX;
170
171     return 0;
172 }
173
174 static size_t av_read(void * h, size_t len, uint8_t * buf) {
175     ByteIOContext * bc = h;
176     return get_buffer(bc, buf, len);
177 }
178
179 static off_t av_seek(void * h, long long pos, int whence) {
180     ByteIOContext * bc = h;
181     if (whence == SEEK_END) {
182         pos = url_fsize(bc) + pos;
183         whence = SEEK_SET;
184     }
185     return url_fseek(bc, pos, whence);
186 }
187
188 static int nut_read_header(AVFormatContext * avf, AVFormatParameters * ap) {
189     NUTContext * priv = avf->priv_data;
190     ByteIOContext * bc = avf->pb;
191     nut_demuxer_opts_tt dopts = {
192         .input = {
193             .priv = bc,
194             .seek = av_seek,
195             .read = av_read,
196             .eof = NULL,
197             .file_pos = 0,
198         },
199         .alloc = { av_malloc, av_realloc, av_free },
200         .read_index = 1,
201         .cache_syncpoints = 1,
202     };
203     nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts);
204     nut_stream_header_tt * s;
205     int ret, i;
206
207     if ((ret = nut_read_headers(nut, &s, NULL))) {
208         av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret));
209         nut_demuxer_uninit(nut);
210         return -1;
211     }
212
213     priv->s = s;
214
215     for (i = 0; s[i].type != -1 && i < 2; i++) {
216         AVStream * st = av_new_stream(avf, i);
217         int j;
218
219         for (j = 0; j < s[i].fourcc_len && j < 8; j++) st->codec->codec_tag |= s[i].fourcc[j]<<(j*8);
220
221         st->codec->has_b_frames = s[i].decode_delay;
222
223         st->codec->extradata_size = s[i].codec_specific_len;
224         if (st->codec->extradata_size) {
225             st->codec->extradata = av_mallocz(st->codec->extradata_size);
226             memcpy(st->codec->extradata, s[i].codec_specific, st->codec->extradata_size);
227         }
228
229         av_set_pts_info(avf->streams[i], 60, s[i].time_base.num, s[i].time_base.den);
230         st->start_time = 0;
231         st->duration = s[i].max_pts;
232
233         st->codec->codec_id = codec_get_id(nut_tags, st->codec->codec_tag);
234
235         switch(s[i].type) {
236         case NUT_AUDIO_CLASS:
237             st->codec->codec_type = CODEC_TYPE_AUDIO;
238             if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = codec_get_id(codec_wav_tags, st->codec->codec_tag);
239
240             st->codec->channels = s[i].channel_count;
241             st->codec->sample_rate = s[i].samplerate_num / s[i].samplerate_denom;
242             break;
243         case NUT_VIDEO_CLASS:
244             st->codec->codec_type = CODEC_TYPE_VIDEO;
245             if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = codec_get_id(codec_bmp_tags, st->codec->codec_tag);
246
247             st->codec->width = s[i].width;
248             st->codec->height = s[i].height;
249             st->sample_aspect_ratio.num = s[i].sample_width;
250             st->sample_aspect_ratio.den = s[i].sample_height;
251             break;
252         }
253         if (st->codec->codec_id == CODEC_ID_NONE) av_log(avf, AV_LOG_ERROR, "Unknown codec?!\n");
254     }
255
256     return 0;
257 }
258
259 static int nut_read_packet(AVFormatContext * avf, AVPacket * pkt) {
260     NUTContext * priv = avf->priv_data;
261     nut_packet_tt pd;
262     int ret;
263
264     ret = nut_read_next_packet(priv->nut, &pd);
265
266     if (ret || av_new_packet(pkt, pd.len) < 0) {
267         if (ret != NUT_ERR_EOF)
268             av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret));
269         return -1;
270     }
271
272     if (pd.flags & NUT_FLAG_KEY) pkt->flags |= PKT_FLAG_KEY;
273     pkt->pts = pd.pts;
274     pkt->stream_index = pd.stream;
275     pkt->pos = url_ftell(avf->pb);
276
277     ret = nut_read_frame(priv->nut, &pd.len, pkt->data);
278
279     return ret;
280 }
281
282 static int nut_read_seek(AVFormatContext * avf, int stream_index, int64_t target_ts, int flags) {
283     NUTContext * priv = avf->priv_data;
284     int active_streams[] = { stream_index, -1 };
285     double time_pos = target_ts * priv->s[stream_index].time_base.num / (double)priv->s[stream_index].time_base.den;
286
287     if (nut_seek(priv->nut, time_pos, 2*!(flags & AVSEEK_FLAG_BACKWARD), active_streams)) return -1;
288
289     return 0;
290 }
291
292 static int nut_read_close(AVFormatContext *s) {
293     NUTContext * priv = s->priv_data;
294
295     nut_demuxer_uninit(priv->nut);
296
297     return 0;
298 }
299
300 AVInputFormat libnut_demuxer = {
301     "libnut",
302     NULL_IF_CONFIG_SMALL("NUT format"),
303     sizeof(NUTContext),
304     nut_probe,
305     nut_read_header,
306     nut_read_packet,
307     nut_read_close,
308     nut_read_seek,
309     .extensions = "nut",
310 };