ffmpeg / libavformat / nuv.c @ 9dd94f83
History | View | Annotate | Download (8.94 KB)
1 | dfca23e3 | Reimar Döffinger | /*
|
---|---|---|---|
2 | * NuppelVideo demuxer.
|
||
3 | 406792e7 | Diego Biurrun | * Copyright (c) 2006 Reimar Doeffinger
|
4 | dfca23e3 | Reimar Döffinger | *
|
5 | 2912e87a | Mans Rullgard | * This file is part of Libav.
|
6 | b78e7197 | Diego Biurrun | *
|
7 | 2912e87a | Mans Rullgard | * Libav is free software; you can redistribute it and/or
|
8 | dfca23e3 | Reimar Döffinger | * modify it under the terms of the GNU Lesser General Public
|
9 | * License as published by the Free Software Foundation; either
|
||
10 | b78e7197 | Diego Biurrun | * version 2.1 of the License, or (at your option) any later version.
|
11 | dfca23e3 | Reimar Döffinger | *
|
12 | 2912e87a | Mans Rullgard | * Libav is distributed in the hope that it will be useful,
|
13 | dfca23e3 | Reimar Döffinger | * 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 | 2912e87a | Mans Rullgard | * License along with Libav; if not, write to the Free Software
|
19 | dfca23e3 | Reimar Döffinger | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
20 | */
|
||
21 | 6a5d31ac | Diego Biurrun | |
22 | #include "libavutil/intreadwrite.h" |
||
23 | dfca23e3 | Reimar Döffinger | #include "avformat.h" |
24 | 9d9f4119 | Måns Rullgård | #include "riff.h" |
25 | dfca23e3 | Reimar Döffinger | |
26 | typedef struct { |
||
27 | int v_id;
|
||
28 | int a_id;
|
||
29 | dd6ca721 | Reimar Döffinger | int rtjpg_video;
|
30 | dfca23e3 | Reimar Döffinger | } NUVContext; |
31 | |||
32 | typedef enum { |
||
33 | NUV_VIDEO = 'V',
|
||
34 | NUV_EXTRADATA = 'D',
|
||
35 | NUV_AUDIO = 'A',
|
||
36 | NUV_SEEKP = 'R',
|
||
37 | NUV_MYTHEXT = 'X'
|
||
38 | b4be9321 | Reimar Döffinger | } nuv_frametype; |
39 | dfca23e3 | Reimar Döffinger | |
40 | static int nuv_probe(AVProbeData *p) { |
||
41 | if (!memcmp(p->buf, "NuppelVideo", 12)) |
||
42 | return AVPROBE_SCORE_MAX;
|
||
43 | if (!memcmp(p->buf, "MythTVVideo", 12)) |
||
44 | return AVPROBE_SCORE_MAX;
|
||
45 | return 0; |
||
46 | } |
||
47 | |||
48 | //! little macro to sanitize packet size
|
||
49 | #define PKTSIZE(s) (s & 0xffffff) |
||
50 | |||
51 | /**
|
||
52 | * \brief read until we found all data needed for decoding
|
||
53 | * \param vst video stream of which to change parameters
|
||
54 | * \param ast video stream of which to change parameters
|
||
55 | * \param myth set if this is a MythTVVideo format file
|
||
56 | * \return 1 if all required codec data was found
|
||
57 | */
|
||
58 | ae628ec1 | Anton Khirnov | static int get_codec_data(AVIOContext *pb, AVStream *vst, |
59 | dfca23e3 | Reimar Döffinger | AVStream *ast, int myth) {
|
60 | b4be9321 | Reimar Döffinger | nuv_frametype frametype; |
61 | dfca23e3 | Reimar Döffinger | if (!vst && !myth)
|
62 | return 1; // no codec data needed |
||
63 | 66e5b1df | Anton Khirnov | while (!pb->eof_reached) {
|
64 | dfca23e3 | Reimar Döffinger | int size, subtype;
|
65 | b7effd4e | Anton Khirnov | frametype = avio_r8(pb); |
66 | dfca23e3 | Reimar Döffinger | switch (frametype) {
|
67 | case NUV_EXTRADATA:
|
||
68 | b7effd4e | Anton Khirnov | subtype = avio_r8(pb); |
69 | 45a8a02a | Anton Khirnov | avio_skip(pb, 6);
|
70 | b7effd4e | Anton Khirnov | size = PKTSIZE(avio_rl32(pb)); |
71 | 50a6c318 | Reimar Döffinger | if (vst && subtype == 'R') { |
72 | dfca23e3 | Reimar Döffinger | vst->codec->extradata_size = size; |
73 | vst->codec->extradata = av_malloc(size); |
||
74 | b7effd4e | Anton Khirnov | avio_read(pb, vst->codec->extradata, size); |
75 | dfca23e3 | Reimar Döffinger | size = 0;
|
76 | if (!myth)
|
||
77 | return 1; |
||
78 | } |
||
79 | break;
|
||
80 | case NUV_MYTHEXT:
|
||
81 | 45a8a02a | Anton Khirnov | avio_skip(pb, 7);
|
82 | b7effd4e | Anton Khirnov | size = PKTSIZE(avio_rl32(pb)); |
83 | dfca23e3 | Reimar Döffinger | if (size != 128 * 4) |
84 | break;
|
||
85 | b7effd4e | Anton Khirnov | avio_rl32(pb); // version
|
86 | dfca23e3 | Reimar Döffinger | if (vst) {
|
87 | b7effd4e | Anton Khirnov | vst->codec->codec_tag = avio_rl32(pb); |
88 | dfca23e3 | Reimar Döffinger | vst->codec->codec_id = |
89 | 1a40491e | Daniel Verkamp | ff_codec_get_id(ff_codec_bmp_tags, vst->codec->codec_tag); |
90 | efd74286 | Reimar Döffinger | if (vst->codec->codec_tag == MKTAG('R', 'J', 'P', 'G')) |
91 | vst->codec->codec_id = CODEC_ID_NUV; |
||
92 | dfca23e3 | Reimar Döffinger | } else
|
93 | 45a8a02a | Anton Khirnov | avio_skip(pb, 4);
|
94 | dfca23e3 | Reimar Döffinger | |
95 | if (ast) {
|
||
96 | b7effd4e | Anton Khirnov | ast->codec->codec_tag = avio_rl32(pb); |
97 | ast->codec->sample_rate = avio_rl32(pb); |
||
98 | ast->codec->bits_per_coded_sample = avio_rl32(pb); |
||
99 | ast->codec->channels = avio_rl32(pb); |
||
100 | dfca23e3 | Reimar Döffinger | ast->codec->codec_id = |
101 | 1a40491e | Daniel Verkamp | ff_wav_codec_get_id(ast->codec->codec_tag, |
102 | dd1c8f3e | Luca Abeni | ast->codec->bits_per_coded_sample); |
103 | 8a59d9a3 | Michael Niedermayer | ast->need_parsing = AVSTREAM_PARSE_FULL; |
104 | dfca23e3 | Reimar Döffinger | } else
|
105 | 45a8a02a | Anton Khirnov | avio_skip(pb, 4 * 4); |
106 | dfca23e3 | Reimar Döffinger | |
107 | size -= 6 * 4; |
||
108 | 45a8a02a | Anton Khirnov | avio_skip(pb, size); |
109 | dfca23e3 | Reimar Döffinger | return 1; |
110 | case NUV_SEEKP:
|
||
111 | size = 11;
|
||
112 | break;
|
||
113 | default:
|
||
114 | 45a8a02a | Anton Khirnov | avio_skip(pb, 7);
|
115 | b7effd4e | Anton Khirnov | size = PKTSIZE(avio_rl32(pb)); |
116 | dfca23e3 | Reimar Döffinger | break;
|
117 | } |
||
118 | 45a8a02a | Anton Khirnov | avio_skip(pb, size); |
119 | dfca23e3 | Reimar Döffinger | } |
120 | return 0; |
||
121 | } |
||
122 | |||
123 | static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) { |
||
124 | e4141433 | Nicholas Tung | NUVContext *ctx = s->priv_data; |
125 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
126 | ac2b2226 | Reimar Döffinger | char id_string[12]; |
127 | dfca23e3 | Reimar Döffinger | double aspect, fps;
|
128 | int is_mythtv, width, height, v_packs, a_packs;
|
||
129 | int stream_nr = 0; |
||
130 | AVStream *vst = NULL, *ast = NULL; |
||
131 | b7effd4e | Anton Khirnov | avio_read(pb, id_string, 12);
|
132 | dfca23e3 | Reimar Döffinger | is_mythtv = !memcmp(id_string, "MythTVVideo", 12); |
133 | 45a8a02a | Anton Khirnov | avio_skip(pb, 5); // version string |
134 | avio_skip(pb, 3); // padding |
||
135 | b7effd4e | Anton Khirnov | width = avio_rl32(pb); |
136 | height = avio_rl32(pb); |
||
137 | avio_rl32(pb); // unused, "desiredwidth"
|
||
138 | avio_rl32(pb); // unused, "desiredheight"
|
||
139 | avio_r8(pb); // 'P' == progressive, 'I' == interlaced
|
||
140 | 45a8a02a | Anton Khirnov | avio_skip(pb, 3); // padding |
141 | b7effd4e | Anton Khirnov | aspect = av_int2dbl(avio_rl64(pb)); |
142 | 4c8e5dfc | Joakim Plate | if (aspect > 0.9999 && aspect < 1.0001) |
143 | aspect = 4.0 / 3.0; |
||
144 | b7effd4e | Anton Khirnov | fps = av_int2dbl(avio_rl64(pb)); |
145 | dfca23e3 | Reimar Döffinger | |
146 | // number of packets per stream type, -1 means unknown, e.g. streaming
|
||
147 | b7effd4e | Anton Khirnov | v_packs = avio_rl32(pb); |
148 | a_packs = avio_rl32(pb); |
||
149 | avio_rl32(pb); // text
|
||
150 | dfca23e3 | Reimar Döffinger | |
151 | b7effd4e | Anton Khirnov | avio_rl32(pb); // keyframe distance (?)
|
152 | dfca23e3 | Reimar Döffinger | |
153 | if (v_packs) {
|
||
154 | ctx->v_id = stream_nr++; |
||
155 | vst = av_new_stream(s, ctx->v_id); |
||
156 | 60583fb6 | Reimar Döffinger | if (!vst)
|
157 | return AVERROR(ENOMEM);
|
||
158 | 72415b2a | Stefano Sabatini | vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
159 | dfca23e3 | Reimar Döffinger | vst->codec->codec_id = CODEC_ID_NUV; |
160 | vst->codec->width = width; |
||
161 | vst->codec->height = height; |
||
162 | dd1c8f3e | Luca Abeni | vst->codec->bits_per_coded_sample = 10;
|
163 | 59729451 | Aurelien Jacobs | vst->sample_aspect_ratio = av_d2q(aspect * height / width, 10000);
|
164 | 8643594c | Michael Niedermayer | vst->r_frame_rate = av_d2q(fps, 60000);
|
165 | dfca23e3 | Reimar Döffinger | av_set_pts_info(vst, 32, 1, 1000); |
166 | } else
|
||
167 | ctx->v_id = -1;
|
||
168 | |||
169 | if (a_packs) {
|
||
170 | ctx->a_id = stream_nr++; |
||
171 | ast = av_new_stream(s, ctx->a_id); |
||
172 | 60583fb6 | Reimar Döffinger | if (!ast)
|
173 | return AVERROR(ENOMEM);
|
||
174 | 72415b2a | Stefano Sabatini | ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
175 | dfca23e3 | Reimar Döffinger | ast->codec->codec_id = CODEC_ID_PCM_S16LE; |
176 | ast->codec->channels = 2;
|
||
177 | ast->codec->sample_rate = 44100;
|
||
178 | ast->codec->bit_rate = 2 * 2 * 44100 * 8; |
||
179 | ast->codec->block_align = 2 * 2; |
||
180 | dd1c8f3e | Luca Abeni | ast->codec->bits_per_coded_sample = 16;
|
181 | dfca23e3 | Reimar Döffinger | av_set_pts_info(ast, 32, 1, 1000); |
182 | } else
|
||
183 | ctx->a_id = -1;
|
||
184 | |||
185 | get_codec_data(pb, vst, ast, is_mythtv); |
||
186 | 00496302 | Reimar Döffinger | ctx->rtjpg_video = vst && vst->codec->codec_id == CODEC_ID_NUV; |
187 | dfca23e3 | Reimar Döffinger | return 0; |
188 | } |
||
189 | |||
190 | #define HDRSIZE 12 |
||
191 | |||
192 | static int nuv_packet(AVFormatContext *s, AVPacket *pkt) { |
||
193 | e4141433 | Nicholas Tung | NUVContext *ctx = s->priv_data; |
194 | ae628ec1 | Anton Khirnov | AVIOContext *pb = s->pb; |
195 | dfca23e3 | Reimar Döffinger | uint8_t hdr[HDRSIZE]; |
196 | b4be9321 | Reimar Döffinger | nuv_frametype frametype; |
197 | dfca23e3 | Reimar Döffinger | int ret, size;
|
198 | 66e5b1df | Anton Khirnov | while (!pb->eof_reached) {
|
199 | dd6ca721 | Reimar Döffinger | int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0; |
200 | a2704c97 | Anton Khirnov | uint64_t pos = avio_tell(pb); |
201 | b7effd4e | Anton Khirnov | ret = avio_read(pb, hdr, HDRSIZE); |
202 | 4e5735f7 | Reimar Döffinger | if (ret < HDRSIZE)
|
203 | return ret < 0 ? ret : AVERROR(EIO); |
||
204 | dfca23e3 | Reimar Döffinger | frametype = hdr[0];
|
205 | fead30d4 | Alex Beregszaszi | size = PKTSIZE(AV_RL32(&hdr[8]));
|
206 | dfca23e3 | Reimar Döffinger | switch (frametype) {
|
207 | case NUV_EXTRADATA:
|
||
208 | dd6ca721 | Reimar Döffinger | if (!ctx->rtjpg_video) {
|
209 | 45a8a02a | Anton Khirnov | avio_skip(pb, size); |
210 | dd6ca721 | Reimar Döffinger | break;
|
211 | } |
||
212 | case NUV_VIDEO:
|
||
213 | dfca23e3 | Reimar Döffinger | if (ctx->v_id < 0) { |
214 | av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n");
|
||
215 | 45a8a02a | Anton Khirnov | avio_skip(pb, size); |
216 | dfca23e3 | Reimar Döffinger | break;
|
217 | } |
||
218 | dd6ca721 | Reimar Döffinger | ret = av_new_packet(pkt, copyhdrsize + size); |
219 | dfca23e3 | Reimar Döffinger | if (ret < 0) |
220 | return ret;
|
||
221 | d71d64dc | Reimar Döffinger | // HACK: we have no idea if it is a keyframe,
|
222 | // but if we mark none seeking will not work at all.
|
||
223 | cc947f04 | Jean-Daniel Dupas | pkt->flags |= AV_PKT_FLAG_KEY; |
224 | fb2e95c9 | Reimar Döffinger | pkt->pos = pos; |
225 | fead30d4 | Alex Beregszaszi | pkt->pts = AV_RL32(&hdr[4]);
|
226 | dfca23e3 | Reimar Döffinger | pkt->stream_index = ctx->v_id; |
227 | dd6ca721 | Reimar Döffinger | memcpy(pkt->data, hdr, copyhdrsize); |
228 | b7effd4e | Anton Khirnov | ret = avio_read(pb, pkt->data + copyhdrsize, size); |
229 | ef12ec23 | Reimar Döffinger | if (ret < 0) { |
230 | av_free_packet(pkt); |
||
231 | return ret;
|
||
232 | } |
||
233 | 94705111 | Reimar Döffinger | if (ret < size)
|
234 | av_shrink_packet(pkt, copyhdrsize + ret); |
||
235 | b0723c8a | Reimar Döffinger | return 0; |
236 | dfca23e3 | Reimar Döffinger | case NUV_AUDIO:
|
237 | if (ctx->a_id < 0) { |
||
238 | av_log(s, AV_LOG_ERROR, "Audio packet in file without audio stream!\n");
|
||
239 | 45a8a02a | Anton Khirnov | avio_skip(pb, size); |
240 | dfca23e3 | Reimar Döffinger | break;
|
241 | } |
||
242 | ret = av_get_packet(pb, pkt, size); |
||
243 | cc947f04 | Jean-Daniel Dupas | pkt->flags |= AV_PKT_FLAG_KEY; |
244 | fb2e95c9 | Reimar Döffinger | pkt->pos = pos; |
245 | fead30d4 | Alex Beregszaszi | pkt->pts = AV_RL32(&hdr[4]);
|
246 | dfca23e3 | Reimar Döffinger | pkt->stream_index = ctx->a_id; |
247 | b0723c8a | Reimar Döffinger | if (ret < 0) return ret; |
248 | return 0; |
||
249 | dfca23e3 | Reimar Döffinger | case NUV_SEEKP:
|
250 | // contains no data, size value is invalid
|
||
251 | break;
|
||
252 | default:
|
||
253 | 45a8a02a | Anton Khirnov | avio_skip(pb, size); |
254 | dfca23e3 | Reimar Döffinger | break;
|
255 | } |
||
256 | } |
||
257 | 6f3e0b21 | Panagiotis Issaris | return AVERROR(EIO);
|
258 | dfca23e3 | Reimar Döffinger | } |
259 | |||
260 | c6610a21 | Diego Elio Pettenò | AVInputFormat ff_nuv_demuxer = { |
261 | dfca23e3 | Reimar Döffinger | "nuv",
|
262 | bde15e74 | Stefano Sabatini | NULL_IF_CONFIG_SMALL("NuppelVideo format"),
|
263 | dfca23e3 | Reimar Döffinger | sizeof(NUVContext),
|
264 | nuv_probe, |
||
265 | nuv_header, |
||
266 | nuv_packet, |
||
267 | NULL,
|
||
268 | NULL,
|
||
269 | 881dad9e | Reimar Döffinger | .flags = AVFMT_GENERIC_INDEX, |
270 | dfca23e3 | Reimar Döffinger | }; |