lavf: move nuv fourcc audio tags from riff to nuv
[ffmpeg.git] / libavformat / nuv.c
1 /*
2  * NuppelVideo demuxer.
3  * Copyright (c) 2006 Reimar Doeffinger
4  *
5  * This file is part of Libav.
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "libavutil/channel_layout.h"
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;
38     int rtjpg_video;
39 } NUVContext;
40
41 typedef enum {
42     NUV_VIDEO = 'V',
43     NUV_EXTRADATA = 'D',
44     NUV_AUDIO = 'A',
45     NUV_SEEKP = 'R',
46     NUV_MYTHEXT = 'X'
47 } nuv_frametype;
48
49 static int nuv_probe(AVProbeData *p) {
50     if (!memcmp(p->buf, "NuppelVideo", 12))
51         return AVPROBE_SCORE_MAX;
52     if (!memcmp(p->buf, "MythTVVideo", 12))
53         return AVPROBE_SCORE_MAX;
54     return 0;
55 }
56
57 /// little macro to sanitize packet size
58 #define PKTSIZE(s) (s &  0xffffff)
59
60 /**
61  * @brief read until we found all data needed for decoding
62  * @param vst video stream of which to change parameters
63  * @param ast video stream of which to change parameters
64  * @param myth set if this is a MythTVVideo format file
65  * @return 1 if all required codec data was found
66  */
67 static int get_codec_data(AVIOContext *pb, AVStream *vst,
68                           AVStream *ast, int myth) {
69     nuv_frametype frametype;
70     if (!vst && !myth)
71         return 1; // no codec data needed
72     while (!pb->eof_reached) {
73         int size, subtype;
74         frametype = avio_r8(pb);
75         switch (frametype) {
76             case NUV_EXTRADATA:
77                 subtype = avio_r8(pb);
78                 avio_skip(pb, 6);
79                 size = PKTSIZE(avio_rl32(pb));
80                 if (vst && subtype == 'R') {
81                     vst->codec->extradata_size = size;
82                     vst->codec->extradata = av_malloc(size);
83                     avio_read(pb, vst->codec->extradata, size);
84                     size = 0;
85                     if (!myth)
86                         return 1;
87                 }
88                 break;
89             case NUV_MYTHEXT:
90                 avio_skip(pb, 7);
91                 size = PKTSIZE(avio_rl32(pb));
92                 if (size != 128 * 4)
93                     break;
94                 avio_rl32(pb); // version
95                 if (vst) {
96                     vst->codec->codec_tag = avio_rl32(pb);
97                     vst->codec->codec_id =
98                         ff_codec_get_id(ff_codec_bmp_tags, vst->codec->codec_tag);
99                     if (vst->codec->codec_tag == MKTAG('R', 'J', 'P', 'G'))
100                         vst->codec->codec_id = AV_CODEC_ID_NUV;
101                 } else
102                     avio_skip(pb, 4);
103
104                 if (ast) {
105                     int id;
106
107                     ast->codec->codec_tag = avio_rl32(pb);
108                     ast->codec->sample_rate = avio_rl32(pb);
109                     ast->codec->bits_per_coded_sample = avio_rl32(pb);
110                     ast->codec->channels = avio_rl32(pb);
111                     ast->codec->channel_layout = 0;
112
113                     id = ff_wav_codec_get_id(ast->codec->codec_tag,
114                                              ast->codec->bits_per_coded_sample);
115                     if (id == AV_CODEC_ID_NONE) {
116                         id = ff_codec_get_id(nuv_audio_tags,
117                                              ast->codec->codec_tag);
118                         if (id == AV_CODEC_ID_PCM_S16LE)
119                             id = ff_get_pcm_codec_id(ast->codec->bits_per_coded_sample,
120                                                      0, 0, ~1);
121                     }
122                     ast->codec->codec_id = id;
123
124                     ast->need_parsing = AVSTREAM_PARSE_FULL;
125                 } else
126                     avio_skip(pb, 4 * 4);
127
128                 size -= 6 * 4;
129                 avio_skip(pb, size);
130                 return 1;
131             case NUV_SEEKP:
132                 size = 11;
133                 break;
134             default:
135                 avio_skip(pb, 7);
136                 size = PKTSIZE(avio_rl32(pb));
137                 break;
138         }
139         avio_skip(pb, size);
140     }
141     return 0;
142 }
143
144 static int nuv_header(AVFormatContext *s) {
145     NUVContext *ctx = s->priv_data;
146     AVIOContext *pb = s->pb;
147     char id_string[12];
148     double aspect, fps;
149     int is_mythtv, width, height, v_packs, a_packs;
150     int stream_nr = 0;
151     AVStream *vst = NULL, *ast = NULL;
152     avio_read(pb, id_string, 12);
153     is_mythtv = !memcmp(id_string, "MythTVVideo", 12);
154     avio_skip(pb, 5); // version string
155     avio_skip(pb, 3); // padding
156     width = avio_rl32(pb);
157     height = avio_rl32(pb);
158     avio_rl32(pb); // unused, "desiredwidth"
159     avio_rl32(pb); // unused, "desiredheight"
160     avio_r8(pb); // 'P' == progressive, 'I' == interlaced
161     avio_skip(pb, 3); // padding
162     aspect = av_int2double(avio_rl64(pb));
163     if (aspect > 0.9999 && aspect < 1.0001)
164         aspect = 4.0 / 3.0;
165     fps = av_int2double(avio_rl64(pb));
166
167     // number of packets per stream type, -1 means unknown, e.g. streaming
168     v_packs = avio_rl32(pb);
169     a_packs = avio_rl32(pb);
170     avio_rl32(pb); // text
171
172     avio_rl32(pb); // keyframe distance (?)
173
174     if (v_packs) {
175         ctx->v_id = stream_nr++;
176         vst = avformat_new_stream(s, NULL);
177         if (!vst)
178             return AVERROR(ENOMEM);
179         vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
180         vst->codec->codec_id = AV_CODEC_ID_NUV;
181         vst->codec->width = width;
182         vst->codec->height = height;
183         vst->codec->bits_per_coded_sample = 10;
184         vst->sample_aspect_ratio = av_d2q(aspect * height / width, 10000);
185 #if FF_API_R_FRAME_RATE
186         vst->r_frame_rate =
187 #endif
188         vst->avg_frame_rate = av_d2q(fps, 60000);
189         avpriv_set_pts_info(vst, 32, 1, 1000);
190     } else
191         ctx->v_id = -1;
192
193     if (a_packs) {
194         ctx->a_id = stream_nr++;
195         ast = avformat_new_stream(s, NULL);
196         if (!ast)
197             return AVERROR(ENOMEM);
198         ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
199         ast->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
200         ast->codec->channels = 2;
201         ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
202         ast->codec->sample_rate = 44100;
203         ast->codec->bit_rate = 2 * 2 * 44100 * 8;
204         ast->codec->block_align = 2 * 2;
205         ast->codec->bits_per_coded_sample = 16;
206         avpriv_set_pts_info(ast, 32, 1, 1000);
207     } else
208         ctx->a_id = -1;
209
210     get_codec_data(pb, vst, ast, is_mythtv);
211     ctx->rtjpg_video = vst && vst->codec->codec_id == AV_CODEC_ID_NUV;
212     return 0;
213 }
214
215 #define HDRSIZE 12
216
217 static int nuv_packet(AVFormatContext *s, AVPacket *pkt) {
218     NUVContext *ctx = s->priv_data;
219     AVIOContext *pb = s->pb;
220     uint8_t hdr[HDRSIZE];
221     nuv_frametype frametype;
222     int ret, size;
223     while (!pb->eof_reached) {
224         int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0;
225         uint64_t pos = avio_tell(pb);
226         ret = avio_read(pb, hdr, HDRSIZE);
227         if (ret < HDRSIZE)
228             return ret < 0 ? ret : AVERROR(EIO);
229         frametype = hdr[0];
230         size = PKTSIZE(AV_RL32(&hdr[8]));
231         switch (frametype) {
232             case NUV_EXTRADATA:
233                 if (!ctx->rtjpg_video) {
234                     avio_skip(pb, size);
235                     break;
236                 }
237             case NUV_VIDEO:
238                 if (ctx->v_id < 0) {
239                     av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n");
240                     avio_skip(pb, size);
241                     break;
242                 }
243                 ret = av_new_packet(pkt, copyhdrsize + size);
244                 if (ret < 0)
245                     return ret;
246                 // HACK: we have no idea if it is a keyframe,
247                 // but if we mark none seeking will not work at all.
248                 pkt->flags |= AV_PKT_FLAG_KEY;
249                 pkt->pos = pos;
250                 pkt->pts = AV_RL32(&hdr[4]);
251                 pkt->stream_index = ctx->v_id;
252                 memcpy(pkt->data, hdr, copyhdrsize);
253                 ret = avio_read(pb, pkt->data + copyhdrsize, size);
254                 if (ret < 0) {
255                     av_free_packet(pkt);
256                     return ret;
257                 }
258                 if (ret < size)
259                     av_shrink_packet(pkt, copyhdrsize + ret);
260                 return 0;
261             case NUV_AUDIO:
262                 if (ctx->a_id < 0) {
263                     av_log(s, AV_LOG_ERROR, "Audio packet in file without audio stream!\n");
264                     avio_skip(pb, size);
265                     break;
266                 }
267                 ret = av_get_packet(pb, pkt, size);
268                 pkt->flags |= AV_PKT_FLAG_KEY;
269                 pkt->pos = pos;
270                 pkt->pts = AV_RL32(&hdr[4]);
271                 pkt->stream_index = ctx->a_id;
272                 if (ret < 0) return ret;
273                 return 0;
274             case NUV_SEEKP:
275                 // contains no data, size value is invalid
276                 break;
277             default:
278                 avio_skip(pb, size);
279                 break;
280         }
281     }
282     return AVERROR(EIO);
283 }
284
285 AVInputFormat ff_nuv_demuxer = {
286     .name           = "nuv",
287     .long_name      = NULL_IF_CONFIG_SMALL("NuppelVideo"),
288     .priv_data_size = sizeof(NUVContext),
289     .read_probe     = nuv_probe,
290     .read_header    = nuv_header,
291     .read_packet    = nuv_packet,
292     .flags          = AVFMT_GENERIC_INDEX,
293 };