libavformat/nuv.c
Go to the documentation of this file.
1 /*
2  * NuppelVideo demuxer.
3  * Copyright (c) 2006 Reimar Doeffinger
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 
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/intfloat.h"
25 #include "avformat.h"
26 #include "internal.h"
27 #include "riff.h"
28 
29 static const AVCodecTag nuv_audio_tags[] = {
30  { AV_CODEC_ID_PCM_S16LE, MKTAG('R', 'A', 'W', 'A') },
31  { AV_CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') },
32  { AV_CODEC_ID_NONE, 0 },
33 };
34 
35 typedef struct {
36  int v_id;
37  int a_id;
39 } NUVContext;
40 
41 typedef enum {
42  NUV_VIDEO = 'V',
44  NUV_AUDIO = 'A',
45  NUV_SEEKP = 'R',
48 
49 static int nuv_probe(AVProbeData *p)
50 {
51  if (!memcmp(p->buf, "NuppelVideo", 12))
52  return AVPROBE_SCORE_MAX;
53  if (!memcmp(p->buf, "MythTVVideo", 12))
54  return AVPROBE_SCORE_MAX;
55  return 0;
56 }
57 
58 /// little macro to sanitize packet size
59 #define PKTSIZE(s) (s & 0xffffff)
60 
61 /**
62  * @brief read until we found all data needed for decoding
63  * @param vst video stream of which to change parameters
64  * @param ast video stream of which to change parameters
65  * @param myth set if this is a MythTVVideo format file
66  * @return 0 or AVERROR code
67  */
68 static int get_codec_data(AVIOContext *pb, AVStream *vst,
69  AVStream *ast, int myth)
70 {
71  nuv_frametype frametype;
72 
73  if (!vst && !myth)
74  return 1; // no codec data needed
75  while (!url_feof(pb)) {
76  int size, subtype;
77 
78  frametype = avio_r8(pb);
79  switch (frametype) {
80  case NUV_EXTRADATA:
81  subtype = avio_r8(pb);
82  avio_skip(pb, 6);
83  size = PKTSIZE(avio_rl32(pb));
84  if (vst && subtype == 'R') {
85  if (vst->codec->extradata) {
86  av_freep(&vst->codec->extradata);
87  vst->codec->extradata_size = 0;
88  }
89  vst->codec->extradata = av_malloc(size);
90  if (!vst->codec->extradata)
91  return AVERROR(ENOMEM);
92  vst->codec->extradata_size = size;
93  avio_read(pb, vst->codec->extradata, size);
94  size = 0;
95  if (!myth)
96  return 0;
97  }
98  break;
99  case NUV_MYTHEXT:
100  avio_skip(pb, 7);
101  size = PKTSIZE(avio_rl32(pb));
102  if (size != 128 * 4)
103  break;
104  avio_rl32(pb); // version
105  if (vst) {
106  vst->codec->codec_tag = avio_rl32(pb);
107  vst->codec->codec_id =
109  if (vst->codec->codec_tag == MKTAG('R', 'J', 'P', 'G'))
111  } else
112  avio_skip(pb, 4);
113 
114  if (ast) {
115  int id;
116 
117  ast->codec->codec_tag = avio_rl32(pb);
118  ast->codec->sample_rate = avio_rl32(pb);
120  ast->codec->channels = avio_rl32(pb);
121  ast->codec->channel_layout = 0;
122 
125  if (id == AV_CODEC_ID_NONE) {
126  id = ff_codec_get_id(nuv_audio_tags, ast->codec->codec_tag);
127  if (id == AV_CODEC_ID_PCM_S16LE)
129  0, 0, ~1);
130  }
131  ast->codec->codec_id = id;
132 
134  } else
135  avio_skip(pb, 4 * 4);
136 
137  size -= 6 * 4;
138  avio_skip(pb, size);
139  return 0;
140  case NUV_SEEKP:
141  size = 11;
142  break;
143  default:
144  avio_skip(pb, 7);
145  size = PKTSIZE(avio_rl32(pb));
146  break;
147  }
148  avio_skip(pb, size);
149  }
150 
151  return 0;
152 }
153 
155 {
156  NUVContext *ctx = s->priv_data;
157  AVIOContext *pb = s->pb;
158  char id_string[12];
159  double aspect, fps;
160  int is_mythtv, width, height, v_packs, a_packs, ret;
161  AVStream *vst = NULL, *ast = NULL;
162 
163  avio_read(pb, id_string, 12);
164  is_mythtv = !memcmp(id_string, "MythTVVideo", 12);
165  avio_skip(pb, 5); // version string
166  avio_skip(pb, 3); // padding
167  width = avio_rl32(pb);
168  height = avio_rl32(pb);
169  avio_rl32(pb); // unused, "desiredwidth"
170  avio_rl32(pb); // unused, "desiredheight"
171  avio_r8(pb); // 'P' == progressive, 'I' == interlaced
172  avio_skip(pb, 3); // padding
173  aspect = av_int2double(avio_rl64(pb));
174  if (aspect > 0.9999 && aspect < 1.0001)
175  aspect = 4.0 / 3.0;
176  fps = av_int2double(avio_rl64(pb));
177 
178  // number of packets per stream type, -1 means unknown, e.g. streaming
179  v_packs = avio_rl32(pb);
180  a_packs = avio_rl32(pb);
181  avio_rl32(pb); // text
182 
183  avio_rl32(pb); // keyframe distance (?)
184 
185  if (v_packs) {
186  vst = avformat_new_stream(s, NULL);
187  if (!vst)
188  return AVERROR(ENOMEM);
189  ctx->v_id = vst->index;
190 
193  vst->codec->width = width;
194  vst->codec->height = height;
195  vst->codec->bits_per_coded_sample = 10;
196  vst->sample_aspect_ratio = av_d2q(aspect * height / width,
197  10000);
198 #if FF_API_R_FRAME_RATE
199  vst->r_frame_rate =
200 #endif
201  vst->avg_frame_rate = av_d2q(fps, 60000);
202  avpriv_set_pts_info(vst, 32, 1, 1000);
203  } else
204  ctx->v_id = -1;
205 
206  if (a_packs) {
207  ast = avformat_new_stream(s, NULL);
208  if (!ast)
209  return AVERROR(ENOMEM);
210  ctx->a_id = ast->index;
211 
212  ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
213  ast->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
214  ast->codec->channels = 2;
215  ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
216  ast->codec->sample_rate = 44100;
217  ast->codec->bit_rate = 2 * 2 * 44100 * 8;
218  ast->codec->block_align = 2 * 2;
219  ast->codec->bits_per_coded_sample = 16;
220  avpriv_set_pts_info(ast, 32, 1, 1000);
221  } else
222  ctx->a_id = -1;
223 
224  if ((ret = get_codec_data(pb, vst, ast, is_mythtv)) < 0)
225  return ret;
226 
227  ctx->rtjpg_video = vst && vst->codec->codec_id == AV_CODEC_ID_NUV;
228 
229  return 0;
230 }
231 
232 #define HDRSIZE 12
233 
235 {
236  NUVContext *ctx = s->priv_data;
237  AVIOContext *pb = s->pb;
238  uint8_t hdr[HDRSIZE];
239  nuv_frametype frametype;
240  int ret, size;
241 
242  while (!url_feof(pb)) {
243  int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0;
244  uint64_t pos = avio_tell(pb);
245 
246  ret = avio_read(pb, hdr, HDRSIZE);
247  if (ret < HDRSIZE)
248  return ret < 0 ? ret : AVERROR(EIO);
249 
250  frametype = hdr[0];
251  size = PKTSIZE(AV_RL32(&hdr[8]));
252 
253  switch (frametype) {
254  case NUV_EXTRADATA:
255  if (!ctx->rtjpg_video) {
256  avio_skip(pb, size);
257  break;
258  }
259  case NUV_VIDEO:
260  if (ctx->v_id < 0) {
261  av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n");
262  avio_skip(pb, size);
263  break;
264  }
265  ret = av_new_packet(pkt, copyhdrsize + size);
266  if (ret < 0)
267  return ret;
268 
269  pkt->pos = pos;
270  pkt->flags |= hdr[2] == 0 ? AV_PKT_FLAG_KEY : 0;
271  pkt->pts = AV_RL32(&hdr[4]);
272  pkt->stream_index = ctx->v_id;
273  memcpy(pkt->data, hdr, copyhdrsize);
274  ret = avio_read(pb, pkt->data + copyhdrsize, size);
275  if (ret < 0) {
276  av_free_packet(pkt);
277  return ret;
278  }
279  if (ret < size)
280  av_shrink_packet(pkt, copyhdrsize + ret);
281  return 0;
282  case NUV_AUDIO:
283  if (ctx->a_id < 0) {
284  av_log(s, AV_LOG_ERROR, "Audio packet in file without audio stream!\n");
285  avio_skip(pb, size);
286  break;
287  }
288  ret = av_get_packet(pb, pkt, size);
289  pkt->flags |= AV_PKT_FLAG_KEY;
290  pkt->pos = pos;
291  pkt->pts = AV_RL32(&hdr[4]);
292  pkt->stream_index = ctx->a_id;
293  if (ret < 0)
294  return ret;
295  return 0;
296  case NUV_SEEKP:
297  // contains no data, size value is invalid
298  break;
299  default:
300  avio_skip(pb, size);
301  break;
302  }
303  }
304 
305  return AVERROR(EIO);
306 }
307 
308 /**
309  * \brief looks for the string RTjjjjjjjjjj in the stream too resync reading
310  * \return 1 if the syncword is found 0 otherwise.
311  */
312 static int nuv_resync(AVFormatContext *s, int64_t pos_limit) {
313  AVIOContext *pb = s->pb;
314  uint32_t tag = 0;
315  while(!url_feof(pb) && avio_tell(pb) < pos_limit) {
316  tag = (tag << 8) | avio_r8(pb);
317  if (tag == MKBETAG('R','T','j','j') &&
318  (tag = avio_rb32(pb)) == MKBETAG('j','j','j','j') &&
319  (tag = avio_rb32(pb)) == MKBETAG('j','j','j','j'))
320  return 1;
321  }
322  return 0;
323 }
324 
325 /**
326  * \brief attempts to read a timestamp from stream at the given stream position
327  * \return timestamp if successful and AV_NOPTS_VALUE if failure
328  */
329 static int64_t nuv_read_dts(AVFormatContext *s, int stream_index,
330  int64_t *ppos, int64_t pos_limit)
331 {
332  NUVContext *ctx = s->priv_data;
333  AVIOContext *pb = s->pb;
334  uint8_t hdr[HDRSIZE];
335  nuv_frametype frametype;
336  int size, key, idx;
337  int64_t pos, dts;
338 
339  if (avio_seek(pb, *ppos, SEEK_SET) < 0)
340  return AV_NOPTS_VALUE;
341 
342  if (!nuv_resync(s, pos_limit))
343  return AV_NOPTS_VALUE;
344 
345  while (!url_feof(pb) && avio_tell(pb) < pos_limit) {
346  if (avio_read(pb, hdr, HDRSIZE) < HDRSIZE)
347  return AV_NOPTS_VALUE;
348  frametype = hdr[0];
349  size = PKTSIZE(AV_RL32(&hdr[8]));
350  switch (frametype) {
351  case NUV_SEEKP:
352  break;
353  case NUV_AUDIO:
354  case NUV_VIDEO:
355  if (frametype == NUV_VIDEO) {
356  idx = ctx->v_id;
357  key = hdr[2] == 0;
358  } else {
359  idx = ctx->a_id;
360  key = 1;
361  }
362  if (stream_index == idx) {
363 
364  pos = avio_tell(s->pb) - HDRSIZE;
365  dts = AV_RL32(&hdr[4]);
366 
367  // TODO - add general support in av_gen_search, so it adds positions after reading timestamps
368  av_add_index_entry(s->streams[stream_index], pos, dts, size + HDRSIZE, 0,
369  key ? AVINDEX_KEYFRAME : 0);
370 
371  *ppos = pos;
372  return dts;
373  }
374  default:
375  avio_skip(pb, size);
376  break;
377  }
378  }
379  return AV_NOPTS_VALUE;
380 }
381 
382 
384  .name = "nuv",
385  .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo"),
386  .priv_data_size = sizeof(NUVContext),
390  .read_timestamp = nuv_read_dts,
392 };
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
void av_free_packet(AVPacket *pkt)
Free a packet.
Definition: avpacket.c:242
int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, int size, int distance, int flags)
Add an index entry into a sorted list.
enum AVCodecID id
Definition: mxfenc.c:89
enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag)
int64_t pos
byte position in stream, -1 if unknown
void av_shrink_packet(AVPacket *pkt, int size)
Reduce packet size, correctly zeroing padding.
Definition: avpacket.c:97
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:709
int index
stream index in AVFormatContext
Definition: avformat.h:644
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:199
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:256
#define AV_CH_LAYOUT_STEREO
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
Format I/O context.
Definition: avformat.h:944
static av_always_inline double av_int2double(uint64_t i)
Reinterpret a 64-bit integer as a double.
Definition: intfloat.h:60
uint8_t
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:610
static AVPacket pkt
Definition: demuxing.c:56
enum AVStreamParseType need_parsing
Definition: avformat.h:811
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
AVStream ** streams
Definition: avformat.h:992
uint8_t * data
uint32_t tag
Definition: movenc.c:894
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
Allocate and read the payload of a packet and initialize its fields with default values.
static int get_codec_data(AVIOContext *pb, AVStream *vst, AVStream *ast, int myth)
read until we found all data needed for decoding
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:248
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
nuv_frametype
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:478
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:73
#define AVINDEX_KEYFRAME
Definition: avformat.h:599
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:579
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
preferred ID for decoding MPEG audio layer 1, 2 or 3
static int64_t nuv_read_dts(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit)
attempts to read a timestamp from stream at the given stream position
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
static int nuv_probe(AVProbeData *p)
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:716
int size
int flags
A combination of AV_PKT_FLAG values.
uint64_t channel_layout
Audio channel layout.
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:469
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:336
audio channel layout utility functions
AVRational av_d2q(double d, int max)
Convert a double precision floating point number to a rational.
Definition: rational.c:106
const AVCodecTag ff_codec_bmp_tags[]
Definition: riff.c:35
static int read_probe(AVProbeData *pd)
ret
Definition: avfilter.c:821
int width
picture width / height.
internal header for RIFF based (de)muxers do NOT include this in end user applications ...
#define AV_RL32
AVInputFormat ff_nuv_demuxer
int url_feof(AVIOContext *s)
feof() equivalent for AVIOContext.
Definition: aviobuf.c:280
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:517
Stream structure.
Definition: avformat.h:643
#define PKTSIZE(s)
little macro to sanitize packet size
NULL
Definition: eval.c:55
#define HDRSIZE
static int width
Definition: tests/utils.c:158
enum AVMediaType codec_type
enum AVCodecID codec_id
int sample_rate
samples per second
AVIOContext * pb
I/O context.
Definition: avformat.h:977
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
unsigned int codec_tag
fourcc (LSB first, so "ABCD" -> (&#39;D&#39;<<24) + (&#39;C&#39;<<16) + (&#39;B&#39;<<8) + &#39;A&#39;).
static int read_packet(AVFormatContext *ctx, AVPacket *pkt)
Definition: libcdio.c:114
BYTE int const BYTE int int int height
Definition: avisynth_c.h:713
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
#define AVFMT_GENERIC_INDEX
Use generic index building code.
Definition: avformat.h:353
enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags)
Select a PCM codec based on the given parameters.
This structure contains the data a format has to probe a file.
Definition: avformat.h:334
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
static int nuv_resync(AVFormatContext *s, int64_t pos_limit)
looks for the string RTjjjjjjjjjj in the stream too resync reading
static int flags
Definition: cpu.c:23
#define AVPROBE_SCORE_MAX
maximum score, half of that is used for file-extension-based detection
Definition: avformat.h:340
full parsing and repack
Definition: avformat.h:582
Main libavformat public API header.
enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps)
static int nuv_packet(AVFormatContext *s, AVPacket *pkt)
#define MKBETAG(a, b, c, d)
Definition: common.h:283
int channels
number of audio channels
void * priv_data
Format private data.
Definition: avformat.h:964
static int nuv_header(AVFormatContext *s)
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:461
static const AVCodecTag nuv_audio_tags[]
#define MKTAG(a, b, c, d)
Definition: common.h:282
AVRational r_frame_rate
Real base framerate of the stream.
Definition: avformat.h:738
This structure stores compressed data.
uint64_t avio_rl64(AVIOContext *s)
Definition: aviobuf.c:587
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:190