]> git.sesse.net Git - ffmpeg/blob - libavformat/riffenc.c
imgconvert: Drop outdated comment block
[ffmpeg] / libavformat / riffenc.c
1 /*
2  * RIFF muxing functions
3  * Copyright (c) 2000 Fabrice Bellard
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/dict.h"
23 #include "libavutil/log.h"
24 #include "libavutil/mathematics.h"
25 #include "libavcodec/avcodec.h"
26 #include "libavcodec/bytestream.h"
27 #include "avformat.h"
28 #include "avio_internal.h"
29 #include "riff.h"
30
31 int64_t ff_start_tag(AVIOContext *pb, const char *tag)
32 {
33     ffio_wfourcc(pb, tag);
34     avio_wl32(pb, 0);
35     return avio_tell(pb);
36 }
37
38 void ff_end_tag(AVIOContext *pb, int64_t start)
39 {
40     int64_t pos;
41
42     pos = avio_tell(pb);
43     avio_seek(pb, start - 4, SEEK_SET);
44     avio_wl32(pb, (uint32_t)(pos - start));
45     avio_seek(pb, pos, SEEK_SET);
46 }
47
48 /* WAVEFORMATEX header */
49 /* returns the size or -1 on error */
50 int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
51 {
52     int bps, blkalign, bytespersec, frame_size;
53     int hdrsize = 18;
54     int waveformatextensible;
55     uint8_t temp[256];
56     uint8_t *riff_extradata       = temp;
57     uint8_t *riff_extradata_start = temp;
58
59     if (!enc->codec_tag || enc->codec_tag > 0xffff)
60         return -1;
61
62     /* We use the known constant frame size for the codec if known, otherwise
63      * fall back on using AVCodecContext.frame_size, which is not as reliable
64      * for indicating packet duration. */
65     frame_size = av_get_audio_frame_duration(enc, enc->block_align);
66
67     waveformatextensible = (enc->channels > 2 && enc->channel_layout) ||
68                            enc->sample_rate > 48000 ||
69                            av_get_bits_per_sample(enc->codec_id) > 16;
70
71     if (waveformatextensible)
72         avio_wl16(pb, 0xfffe);
73     else
74         avio_wl16(pb, enc->codec_tag);
75
76     avio_wl16(pb, enc->channels);
77     avio_wl32(pb, enc->sample_rate);
78     if (enc->codec_id == AV_CODEC_ID_MP2 ||
79         enc->codec_id == AV_CODEC_ID_MP3 ||
80         enc->codec_id == AV_CODEC_ID_GSM_MS) {
81         bps = 0;
82     } else {
83         if (!(bps = av_get_bits_per_sample(enc->codec_id))) {
84             if (enc->bits_per_coded_sample)
85                 bps = enc->bits_per_coded_sample;
86             else
87                 bps = 16;  // default to 16
88         }
89     }
90     if (bps != enc->bits_per_coded_sample && enc->bits_per_coded_sample) {
91         av_log(enc, AV_LOG_WARNING,
92                "requested bits_per_coded_sample (%d) "
93                "and actually stored (%d) differ\n",
94                enc->bits_per_coded_sample, bps);
95     }
96
97     if (enc->codec_id == AV_CODEC_ID_MP2) {
98         blkalign = frame_size;
99     } else if (enc->codec_id == AV_CODEC_ID_MP3) {
100         blkalign = 576 * (enc->sample_rate <= 24000 ? 1 : 2);
101     } else if (enc->codec_id == AV_CODEC_ID_AC3) {
102         blkalign = 3840;                /* maximum bytes per frame */
103     } else if (enc->block_align != 0) { /* specified by the codec */
104         blkalign = enc->block_align;
105     } else
106         blkalign = bps * enc->channels / av_gcd(8, bps);
107     if (enc->codec_id == AV_CODEC_ID_PCM_U8 ||
108         enc->codec_id == AV_CODEC_ID_PCM_S24LE ||
109         enc->codec_id == AV_CODEC_ID_PCM_S32LE ||
110         enc->codec_id == AV_CODEC_ID_PCM_F32LE ||
111         enc->codec_id == AV_CODEC_ID_PCM_F64LE ||
112         enc->codec_id == AV_CODEC_ID_PCM_S16LE) {
113         bytespersec = enc->sample_rate * blkalign;
114     } else {
115         bytespersec = enc->bit_rate / 8;
116     }
117     avio_wl32(pb, bytespersec); /* bytes per second */
118     avio_wl16(pb, blkalign);    /* block align */
119     avio_wl16(pb, bps);         /* bits per sample */
120     if (enc->codec_id == AV_CODEC_ID_MP3) {
121         hdrsize += 12;
122         bytestream_put_le16(&riff_extradata, 1);    /* wID */
123         bytestream_put_le32(&riff_extradata, 2);    /* fdwFlags */
124         bytestream_put_le16(&riff_extradata, 1152); /* nBlockSize */
125         bytestream_put_le16(&riff_extradata, 1);    /* nFramesPerBlock */
126         bytestream_put_le16(&riff_extradata, 1393); /* nCodecDelay */
127     } else if (enc->codec_id == AV_CODEC_ID_MP2) {
128         hdrsize += 22;
129         /* fwHeadLayer */
130         bytestream_put_le16(&riff_extradata, 2);
131         /* dwHeadBitrate */
132         bytestream_put_le32(&riff_extradata, enc->bit_rate);
133         /* fwHeadMode */
134         bytestream_put_le16(&riff_extradata, enc->channels == 2 ? 1 : 8);
135         /* fwHeadModeExt */
136         bytestream_put_le16(&riff_extradata, 0);
137         /* wHeadEmphasis */
138         bytestream_put_le16(&riff_extradata, 1);
139         /* fwHeadFlags */
140         bytestream_put_le16(&riff_extradata, 16);
141         /* dwPTSLow */
142         bytestream_put_le32(&riff_extradata, 0);
143         /* dwPTSHigh */
144         bytestream_put_le32(&riff_extradata, 0);
145     } else if (enc->codec_id == AV_CODEC_ID_GSM_MS ||
146                enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
147         hdrsize += 2;
148         /* wSamplesPerBlock */
149         bytestream_put_le16(&riff_extradata, frame_size);
150     } else if (enc->extradata_size) {
151         riff_extradata_start = enc->extradata;
152         riff_extradata       = enc->extradata + enc->extradata_size;
153         hdrsize             += enc->extradata_size;
154     }
155     /* write WAVEFORMATEXTENSIBLE extensions */
156     if (waveformatextensible) {
157         hdrsize += 22;
158         /* 22 is WAVEFORMATEXTENSIBLE size */
159         avio_wl16(pb, riff_extradata - riff_extradata_start + 22);
160         /* ValidBitsPerSample || SamplesPerBlock || Reserved */
161         avio_wl16(pb, bps);
162         /* dwChannelMask */
163         avio_wl32(pb, enc->channel_layout);
164         /* GUID + next 3 */
165         avio_wl32(pb, enc->codec_tag);
166         avio_wl32(pb, 0x00100000);
167         avio_wl32(pb, 0xAA000080);
168         avio_wl32(pb, 0x719B3800);
169     } else {
170         avio_wl16(pb, riff_extradata - riff_extradata_start); /* cbSize */
171     }
172     avio_write(pb, riff_extradata_start, riff_extradata - riff_extradata_start);
173     if (hdrsize & 1) {
174         hdrsize++;
175         avio_w8(pb, 0);
176     }
177
178     return hdrsize;
179 }
180
181 /* BITMAPINFOHEADER header */
182 void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc,
183                        const AVCodecTag *tags, int for_asf)
184 {
185     /* size */
186     avio_wl32(pb, 40 + enc->extradata_size);
187     avio_wl32(pb, enc->width);
188     //We always store RGB TopDown
189     avio_wl32(pb, enc->codec_tag ? enc->height : -enc->height);
190     /* planes */
191     avio_wl16(pb, 1);
192     /* depth */
193     avio_wl16(pb, enc->bits_per_coded_sample ? enc->bits_per_coded_sample : 24);
194     /* compression type */
195     avio_wl32(pb, enc->codec_tag);
196     avio_wl32(pb, enc->width * enc->height * 3);
197     avio_wl32(pb, 0);
198     avio_wl32(pb, 0);
199     avio_wl32(pb, 0);
200     avio_wl32(pb, 0);
201
202     avio_write(pb, enc->extradata, enc->extradata_size);
203
204     if (!for_asf && enc->extradata_size & 1)
205         avio_w8(pb, 0);
206 }
207
208 void ff_parse_specific_params(AVStream *st, int *au_rate,
209                               int *au_ssize, int *au_scale)
210 {
211     AVCodecContext *codec = st->codec;
212     int gcd;
213     int audio_frame_size;
214
215     audio_frame_size = av_get_audio_frame_duration(codec, 0);
216
217     *au_ssize = codec->block_align;
218     if (audio_frame_size && codec->sample_rate) {
219         *au_scale = audio_frame_size;
220         *au_rate  = codec->sample_rate;
221     } else if (codec->codec_type == AVMEDIA_TYPE_VIDEO ||
222                codec->codec_type == AVMEDIA_TYPE_DATA ||
223                codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
224         *au_scale = st->time_base.num;
225         *au_rate  = st->time_base.den;
226     } else {
227         *au_scale = codec->block_align ? codec->block_align * 8 : 8;
228         *au_rate  = codec->bit_rate ? codec->bit_rate :
229                     8 * codec->sample_rate;
230     }
231     gcd        = av_gcd(*au_scale, *au_rate);
232     *au_scale /= gcd;
233     *au_rate  /= gcd;
234 }
235
236 void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str)
237 {
238     int len = strlen(str);
239     if (len > 0) {
240         len++;
241         ffio_wfourcc(pb, tag);
242         avio_wl32(pb, len);
243         avio_put_str(pb, str);
244         if (len & 1)
245             avio_w8(pb, 0);
246     }
247 }
248
249 static const char riff_tags[][5] = {
250     "IARL", "IART", "ICMS", "ICMT", "ICOP", "ICRD", "ICRP", "IDIM", "IDPI",
251     "IENG", "IGNR", "IKEY", "ILGT", "ILNG", "IMED", "INAM", "IPLT", "IPRD",
252     "IPRT", "ITRK", "ISBJ", "ISFT", "ISHP", "ISMP", "ISRC", "ISRF", "ITCH",
253     { 0 }
254 };
255
256 static int riff_has_valid_tags(AVFormatContext *s)
257 {
258     int i;
259
260     for (i = 0; *riff_tags[i]; i++)
261         if (av_dict_get(s->metadata, riff_tags[i], NULL, AV_DICT_MATCH_CASE))
262             return 1;
263
264     return 0;
265 }
266
267 void ff_riff_write_info(AVFormatContext *s)
268 {
269     AVIOContext *pb = s->pb;
270     int i;
271     int64_t list_pos;
272     AVDictionaryEntry *t = NULL;
273
274     ff_metadata_conv(&s->metadata, ff_riff_info_conv, NULL);
275
276     /* writing empty LIST is not nice and may cause problems */
277     if (!riff_has_valid_tags(s))
278         return;
279
280     list_pos = ff_start_tag(pb, "LIST");
281     ffio_wfourcc(pb, "INFO");
282     for (i = 0; *riff_tags[i]; i++)
283         if ((t = av_dict_get(s->metadata, riff_tags[i],
284                              NULL, AV_DICT_MATCH_CASE)))
285             ff_riff_write_info_tag(s->pb, t->key, t->value);
286     ff_end_tag(pb, list_pos);
287 }