ffmpeg / libavformat / libnut.c @ a2704c97
History | View | Annotate | Download (9.06 KB)
1 | eca06097 | Diego Biurrun | /*
|
---|---|---|---|
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 | 0020596f | Oded Shimon | /**
|
23 | ba87f080 | Diego Biurrun | * @file
|
24 | 0020596f | Oded Shimon | * NUT demuxing and muxing via libnut.
|
25 | * @author Oded Shimon <ods15@ods15.dyndns.org>
|
||
26 | */
|
||
27 | |||
28 | f956e129 | Oded Shimon | #include "avformat.h" |
29 | #include "riff.h" |
||
30 | 4d8aa1c3 | Oded Shimon | #include <libnut.h> |
31 | f956e129 | Oded Shimon | |
32 | #define ID_STRING "nut/multimedia container" |
||
33 | #define ID_LENGTH (strlen(ID_STRING) + 1) |
||
34 | |||
35 | typedef struct { |
||
36 | bffc76bd | Oded Shimon | nut_context_tt * nut; |
37 | nut_stream_header_tt * s; |
||
38 | f956e129 | Oded Shimon | } NUTContext; |
39 | |||
40 | 7caf0cc6 | Michael Niedermayer | static const AVCodecTag nut_tags[] = { |
41 | 468f8102 | Oded Shimon | { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') }, |
42 | f956e129 | Oded Shimon | { CODEC_ID_MP3, MKTAG('m', 'p', '3', ' ') }, |
43 | { CODEC_ID_VORBIS, MKTAG('v', 'r', 'b', 's') }, |
||
44 | { 0, 0 }, |
||
45 | }; |
||
46 | |||
47 | b250f9c6 | Aurelien Jacobs | #if CONFIG_LIBNUT_MUXER
|
48 | f956e129 | Oded Shimon | static int av_write(void * h, size_t len, const uint8_t * buf) { |
49 | ae628ec1 | Anton Khirnov | AVIOContext * bc = h; |
50 | 77eb5504 | Anton Khirnov | avio_write(bc, buf, len); |
51 | f956e129 | Oded Shimon | //put_flush_packet(bc);
|
52 | return len;
|
||
53 | } |
||
54 | |||
55 | static int nut_write_header(AVFormatContext * avf) { |
||
56 | NUTContext * priv = avf->priv_data; |
||
57 | ae628ec1 | Anton Khirnov | AVIOContext * bc = avf->pb; |
58 | bffc76bd | Oded Shimon | nut_muxer_opts_tt mopts = { |
59 | f956e129 | Oded Shimon | .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 | bf054f74 | Oded Shimon | .fti = NULL,
|
68 | f956e129 | Oded Shimon | }; |
69 | bffc76bd | Oded Shimon | nut_stream_header_tt * s; |
70 | f956e129 | Oded Shimon | 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 | d7d3efae | Oded Shimon | int num, denom, ssize;
|
79 | f956e129 | Oded Shimon | |
80 | 72415b2a | Stefano Sabatini | s[i].type = codec->codec_type == AVMEDIA_TYPE_VIDEO ? NUT_VIDEO_CLASS : NUT_AUDIO_CLASS; |
81 | f956e129 | Oded Shimon | |
82 | if (codec->codec_tag) fourcc = codec->codec_tag;
|
||
83 | 1a40491e | Daniel Verkamp | else fourcc = ff_codec_get_tag(nut_tags, codec->codec_id);
|
84 | f956e129 | Oded Shimon | |
85 | if (!fourcc) {
|
||
86 | 72415b2a | Stefano Sabatini | if (codec->codec_type == AVMEDIA_TYPE_VIDEO) fourcc = ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id);
|
87 | if (codec->codec_type == AVMEDIA_TYPE_AUDIO) fourcc = ff_codec_get_tag(ff_codec_wav_tags, codec->codec_id);
|
||
88 | f956e129 | Oded Shimon | } |
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 | d7d3efae | Oded Shimon | ff_parse_specific_params(codec, &num, &ssize, &denom); |
95 | av_set_pts_info(avf->streams[i], 60, denom, num);
|
||
96 | f956e129 | Oded Shimon | |
97 | d7d3efae | Oded Shimon | s[i].time_base.num = denom; |
98 | s[i].time_base.den = num; |
||
99 | f956e129 | Oded Shimon | |
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 | 72415b2a | Stefano Sabatini | if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
106 | f956e129 | Oded Shimon | 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 | d7d3efae | Oded Shimon | s[i].samplerate_num = codec->sample_rate; |
113 | f956e129 | Oded Shimon | 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 | bffc76bd | Oded Shimon | nut_packet_tt p; |
127 | f956e129 | Oded Shimon | |
128 | p.len = pkt->size; |
||
129 | p.stream = pkt->stream_index; |
||
130 | p.pts = pkt->pts; |
||
131 | cc947f04 | Jean-Daniel Dupas | p.flags = pkt->flags & AV_PKT_FLAG_KEY ? NUT_FLAG_KEY : 0;
|
132 | f956e129 | Oded Shimon | 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 | ae628ec1 | Anton Khirnov | AVIOContext * bc = avf->pb; |
141 | f956e129 | Oded Shimon | 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 | c6610a21 | Diego Elio Pettenò | AVOutputFormat ff_libnut_muxer = { |
154 | 0d49b9ad | Diego Biurrun | "libnut",
|
155 | f956e129 | Oded Shimon | "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 | 8212568a | Diego Biurrun | #endif /* CONFIG_LIBNUT_MUXER */ |
167 | f956e129 | Oded Shimon | |
168 | static int nut_probe(AVProbeData *p) { |
||
169 | 87e87886 | Michael Niedermayer | if (!memcmp(p->buf, ID_STRING, ID_LENGTH)) return AVPROBE_SCORE_MAX; |
170 | f956e129 | Oded Shimon | |
171 | return 0; |
||
172 | } |
||
173 | |||
174 | static size_t av_read(void * h, size_t len, uint8_t * buf) { |
||
175 | ae628ec1 | Anton Khirnov | AVIOContext * bc = h; |
176 | b7effd4e | Anton Khirnov | return avio_read(bc, buf, len);
|
177 | f956e129 | Oded Shimon | } |
178 | |||
179 | static off_t av_seek(void * h, long long pos, int whence) { |
||
180 | ae628ec1 | Anton Khirnov | AVIOContext * bc = h; |
181 | f956e129 | Oded Shimon | if (whence == SEEK_END) {
|
182 | pos = url_fsize(bc) + pos; |
||
183 | whence = SEEK_SET; |
||
184 | } |
||
185 | 6b4aa5da | Anton Khirnov | return avio_seek(bc, pos, whence);
|
186 | f956e129 | Oded Shimon | } |
187 | |||
188 | static int nut_read_header(AVFormatContext * avf, AVFormatParameters * ap) { |
||
189 | NUTContext * priv = avf->priv_data; |
||
190 | ae628ec1 | Anton Khirnov | AVIOContext * bc = avf->pb; |
191 | bffc76bd | Oded Shimon | nut_demuxer_opts_tt dopts = { |
192 | f956e129 | Oded Shimon | .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 | 0d666a47 | Oded Shimon | .read_index = 1,
|
201 | .cache_syncpoints = 1,
|
||
202 | f956e129 | Oded Shimon | }; |
203 | bffc76bd | Oded Shimon | nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts); |
204 | nut_stream_header_tt * s; |
||
205 | f956e129 | Oded Shimon | int ret, i;
|
206 | |||
207 | if ((ret = nut_read_headers(nut, &s, NULL))) { |
||
208 | e4bb7083 | Oded Shimon | av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret));
|
209 | f956e129 | Oded Shimon | 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 | d7d3efae | Oded Shimon | av_set_pts_info(avf->streams[i], 60, s[i].time_base.num, s[i].time_base.den);
|
230 | f956e129 | Oded Shimon | st->start_time = 0;
|
231 | st->duration = s[i].max_pts; |
||
232 | |||
233 | 1a40491e | Daniel Verkamp | st->codec->codec_id = ff_codec_get_id(nut_tags, st->codec->codec_tag); |
234 | f956e129 | Oded Shimon | |
235 | switch(s[i].type) {
|
||
236 | case NUT_AUDIO_CLASS:
|
||
237 | 72415b2a | Stefano Sabatini | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
238 | 1a40491e | Daniel Verkamp | if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, st->codec->codec_tag);
|
239 | f956e129 | Oded Shimon | |
240 | st->codec->channels = s[i].channel_count; |
||
241 | d7d3efae | Oded Shimon | st->codec->sample_rate = s[i].samplerate_num / s[i].samplerate_denom; |
242 | f956e129 | Oded Shimon | break;
|
243 | case NUT_VIDEO_CLASS:
|
||
244 | 72415b2a | Stefano Sabatini | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
245 | 1a40491e | Daniel Verkamp | if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, st->codec->codec_tag);
|
246 | f956e129 | Oded Shimon | |
247 | st->codec->width = s[i].width; |
||
248 | st->codec->height = s[i].height; |
||
249 | 59729451 | Aurelien Jacobs | st->sample_aspect_ratio.num = s[i].sample_width; |
250 | st->sample_aspect_ratio.den = s[i].sample_height; |
||
251 | f956e129 | Oded Shimon | 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 | bffc76bd | Oded Shimon | nut_packet_tt pd; |
262 | f956e129 | Oded Shimon | int ret;
|
263 | |||
264 | e4bb7083 | Oded Shimon | ret = nut_read_next_packet(priv->nut, &pd); |
265 | f956e129 | Oded Shimon | |
266 | e4bb7083 | Oded Shimon | 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 | f956e129 | Oded Shimon | |
272 | cc947f04 | Jean-Daniel Dupas | if (pd.flags & NUT_FLAG_KEY) pkt->flags |= AV_PKT_FLAG_KEY;
|
273 | f956e129 | Oded Shimon | pkt->pts = pd.pts; |
274 | pkt->stream_index = pd.stream; |
||
275 | a2704c97 | Anton Khirnov | pkt->pos = avio_tell(avf->pb); |
276 | f956e129 | Oded Shimon | |
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 | d7d3efae | Oded Shimon | double time_pos = target_ts * priv->s[stream_index].time_base.num / (double)priv->s[stream_index].time_base.den; |
286 | f956e129 | Oded Shimon | |
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 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_libnut_demuxer = { |
301 | 5fdb9cc5 | Ramiro Polla | "libnut",
|
302 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("NUT format"),
|
303 | f956e129 | Oded Shimon | 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 | }; |