3 * Copyright (c) 2006 Reimar Doeffinger
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/channel_layout.h"
23 #include "libavutil/imgutils.h"
24 #include "libavutil/intreadwrite.h"
25 #include "libavutil/intfloat.h"
30 static const AVCodecTag nuv_audio_tags
[] = {
31 { AV_CODEC_ID_PCM_S16LE
, MKTAG('R', 'A', 'W', 'A') },
32 { AV_CODEC_ID_MP3
, MKTAG('L', 'A', 'M', 'E') },
33 { AV_CODEC_ID_NONE
, 0 },
36 typedef struct NUVContext
{
50 static int nuv_probe(AVProbeData
*p
)
52 if (!memcmp(p
->buf
, "NuppelVideo", 12))
53 return AVPROBE_SCORE_MAX
;
54 if (!memcmp(p
->buf
, "MythTVVideo", 12))
55 return AVPROBE_SCORE_MAX
;
59 /// little macro to sanitize packet size
60 #define PKTSIZE(s) (s & 0xffffff)
63 * @brief read until we found all data needed for decoding
64 * @param vst video stream of which to change parameters
65 * @param ast video stream of which to change parameters
66 * @param myth set if this is a MythTVVideo format file
67 * @return 0 or AVERROR code
69 static int get_codec_data(AVIOContext
*pb
, AVStream
*vst
,
70 AVStream
*ast
, int myth
)
72 nuv_frametype frametype
;
75 return 1; // no codec data needed
76 while (!pb
->eof_reached
) {
79 frametype
= avio_r8(pb
);
82 subtype
= avio_r8(pb
);
84 size
= PKTSIZE(avio_rl32(pb
));
85 if (vst
&& subtype
== 'R') {
86 if (vst
->codec
->extradata
) {
87 av_freep(&vst
->codec
->extradata
);
88 vst
->codec
->extradata_size
= 0;
90 vst
->codec
->extradata
= av_malloc(size
);
91 if (!vst
->codec
->extradata
)
92 return AVERROR(ENOMEM
);
93 vst
->codec
->extradata_size
= size
;
94 avio_read(pb
, vst
->codec
->extradata
, size
);
102 size
= PKTSIZE(avio_rl32(pb
));
105 avio_rl32(pb
); // version
107 vst
->codec
->codec_tag
= avio_rl32(pb
);
108 vst
->codec
->codec_id
=
109 ff_codec_get_id(ff_codec_bmp_tags
, vst
->codec
->codec_tag
);
110 if (vst
->codec
->codec_tag
== MKTAG('R', 'J', 'P', 'G'))
111 vst
->codec
->codec_id
= AV_CODEC_ID_NUV
;
118 ast
->codec
->codec_tag
= avio_rl32(pb
);
119 ast
->codec
->sample_rate
= avio_rl32(pb
);
120 ast
->codec
->bits_per_coded_sample
= avio_rl32(pb
);
121 ast
->codec
->channels
= avio_rl32(pb
);
122 ast
->codec
->channel_layout
= 0;
124 id
= ff_wav_codec_get_id(ast
->codec
->codec_tag
,
125 ast
->codec
->bits_per_coded_sample
);
126 if (id
== AV_CODEC_ID_NONE
) {
127 id
= ff_codec_get_id(nuv_audio_tags
, ast
->codec
->codec_tag
);
128 if (id
== AV_CODEC_ID_PCM_S16LE
)
129 id
= ff_get_pcm_codec_id(ast
->codec
->bits_per_coded_sample
,
132 ast
->codec
->codec_id
= id
;
134 ast
->need_parsing
= AVSTREAM_PARSE_FULL
;
136 avio_skip(pb
, 4 * 4);
146 size
= PKTSIZE(avio_rl32(pb
));
155 static int nuv_header(AVFormatContext
*s
)
157 NUVContext
*ctx
= s
->priv_data
;
158 AVIOContext
*pb
= s
->pb
;
161 int is_mythtv
, width
, height
, v_packs
, a_packs
, ret
;
162 AVStream
*vst
= NULL
, *ast
= NULL
;
164 avio_read(pb
, id_string
, 12);
165 is_mythtv
= !memcmp(id_string
, "MythTVVideo", 12);
166 avio_skip(pb
, 5); // version string
167 avio_skip(pb
, 3); // padding
168 width
= avio_rl32(pb
);
169 height
= avio_rl32(pb
);
170 avio_rl32(pb
); // unused, "desiredwidth"
171 avio_rl32(pb
); // unused, "desiredheight"
172 avio_r8(pb
); // 'P' == progressive, 'I' == interlaced
173 avio_skip(pb
, 3); // padding
174 aspect
= av_int2double(avio_rl64(pb
));
175 if (aspect
> 0.9999 && aspect
< 1.0001)
177 fps
= av_int2double(avio_rl64(pb
));
179 if (s
->error_recognition
& AV_EF_EXPLODE
) {
180 av_log(s
, AV_LOG_ERROR
, "Invalid frame rate %f\n", fps
);
181 return AVERROR_INVALIDDATA
;
183 av_log(s
, AV_LOG_WARNING
, "Invalid frame rate %f, setting to 0.\n", fps
);
188 // number of packets per stream type, -1 means unknown, e.g. streaming
189 v_packs
= avio_rl32(pb
);
190 a_packs
= avio_rl32(pb
);
191 avio_rl32(pb
); // text
193 avio_rl32(pb
); // keyframe distance (?)
196 vst
= avformat_new_stream(s
, NULL
);
198 return AVERROR(ENOMEM
);
199 ctx
->v_id
= vst
->index
;
201 ret
= av_image_check_size(width
, height
, 0, ctx
);
205 vst
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
206 vst
->codec
->codec_id
= AV_CODEC_ID_NUV
;
207 vst
->codec
->width
= width
;
208 vst
->codec
->height
= height
;
209 vst
->codec
->bits_per_coded_sample
= 10;
210 vst
->sample_aspect_ratio
= av_d2q(aspect
* height
/ width
,
212 vst
->avg_frame_rate
= av_d2q(fps
, 60000);
213 avpriv_set_pts_info(vst
, 32, 1, 1000);
218 ast
= avformat_new_stream(s
, NULL
);
220 return AVERROR(ENOMEM
);
221 ctx
->a_id
= ast
->index
;
223 ast
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
224 ast
->codec
->codec_id
= AV_CODEC_ID_PCM_S16LE
;
225 ast
->codec
->channels
= 2;
226 ast
->codec
->channel_layout
= AV_CH_LAYOUT_STEREO
;
227 ast
->codec
->sample_rate
= 44100;
228 ast
->codec
->bit_rate
= 2 * 2 * 44100 * 8;
229 ast
->codec
->block_align
= 2 * 2;
230 ast
->codec
->bits_per_coded_sample
= 16;
231 avpriv_set_pts_info(ast
, 32, 1, 1000);
235 if ((ret
= get_codec_data(pb
, vst
, ast
, is_mythtv
)) < 0)
238 ctx
->rtjpg_video
= vst
&& vst
->codec
->codec_id
== AV_CODEC_ID_NUV
;
245 static int nuv_packet(AVFormatContext
*s
, AVPacket
*pkt
)
247 NUVContext
*ctx
= s
->priv_data
;
248 AVIOContext
*pb
= s
->pb
;
249 uint8_t hdr
[HDRSIZE
];
250 nuv_frametype frametype
;
253 while (!pb
->eof_reached
) {
254 int copyhdrsize
= ctx
->rtjpg_video ? HDRSIZE
: 0;
255 uint64_t pos
= avio_tell(pb
);
257 ret
= avio_read(pb
, hdr
, HDRSIZE
);
259 return ret
< 0 ? ret
: AVERROR(EIO
);
262 size
= PKTSIZE(AV_RL32(&hdr
[8]));
266 if (!ctx
->rtjpg_video
) {
272 av_log(s
, AV_LOG_ERROR
, "Video packet in file without video stream!\n");
276 ret
= av_new_packet(pkt
, copyhdrsize
+ size
);
279 // HACK: we have no idea if it is a keyframe,
280 // but if we mark none seeking will not work at all.
281 pkt
->flags
|= AV_PKT_FLAG_KEY
;
283 pkt
->pts
= AV_RL32(&hdr
[4]);
284 pkt
->stream_index
= ctx
->v_id
;
285 memcpy(pkt
->data
, hdr
, copyhdrsize
);
286 ret
= avio_read(pb
, pkt
->data
+ copyhdrsize
, size
);
288 av_packet_unref(pkt
);
292 av_shrink_packet(pkt
, copyhdrsize
+ ret
);
296 av_log(s
, AV_LOG_ERROR
, "Audio packet in file without audio stream!\n");
300 ret
= av_get_packet(pb
, pkt
, size
);
301 pkt
->flags
|= AV_PKT_FLAG_KEY
;
303 pkt
->pts
= AV_RL32(&hdr
[4]);
304 pkt
->stream_index
= ctx
->a_id
;
309 // contains no data, size value is invalid
320 AVInputFormat ff_nuv_demuxer
= {
322 .long_name
= NULL_IF_CONFIG_SMALL("NuppelVideo"),
323 .priv_data_size
= sizeof(NUVContext
),
324 .read_probe
= nuv_probe
,
325 .read_header
= nuv_header
,
326 .read_packet
= nuv_packet
,
327 .flags
= AVFMT_GENERIC_INDEX
,