annotate ffmpeg/libavformat/wavenc.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * WAV muxer
yading@11 3 * Copyright (c) 2001, 2002 Fabrice Bellard
yading@11 4 *
yading@11 5 * Sony Wave64 muxer
yading@11 6 * Copyright (c) 2012 Paul B Mahol
yading@11 7 *
yading@11 8 * WAV muxer RF64 support
yading@11 9 * Copyright (c) 2013 Daniel Verkamp <daniel@drv.nu>
yading@11 10 *
yading@11 11 * This file is part of FFmpeg.
yading@11 12 *
yading@11 13 * FFmpeg is free software; you can redistribute it and/or
yading@11 14 * modify it under the terms of the GNU Lesser General Public
yading@11 15 * License as published by the Free Software Foundation; either
yading@11 16 * version 2.1 of the License, or (at your option) any later version.
yading@11 17 *
yading@11 18 * FFmpeg is distributed in the hope that it will be useful,
yading@11 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 21 * Lesser General Public License for more details.
yading@11 22 *
yading@11 23 * You should have received a copy of the GNU Lesser General Public
yading@11 24 * License along with FFmpeg; if not, write to the Free Software
yading@11 25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 26 */
yading@11 27
yading@11 28 #include <stdint.h>
yading@11 29 #include <string.h>
yading@11 30
yading@11 31 #include "libavutil/dict.h"
yading@11 32 #include "libavutil/common.h"
yading@11 33 #include "libavutil/mathematics.h"
yading@11 34 #include "libavutil/opt.h"
yading@11 35
yading@11 36 #include "avformat.h"
yading@11 37 #include "avio.h"
yading@11 38 #include "avio_internal.h"
yading@11 39 #include "internal.h"
yading@11 40 #include "riff.h"
yading@11 41
yading@11 42 #define RF64_AUTO (-1)
yading@11 43 #define RF64_NEVER 0
yading@11 44 #define RF64_ALWAYS 1
yading@11 45
yading@11 46 typedef struct WAVMuxContext {
yading@11 47 const AVClass *class;
yading@11 48 int64_t data;
yading@11 49 int64_t fact_pos;
yading@11 50 int64_t ds64;
yading@11 51 int64_t minpts;
yading@11 52 int64_t maxpts;
yading@11 53 int last_duration;
yading@11 54 int write_bext;
yading@11 55 int rf64;
yading@11 56 } WAVMuxContext;
yading@11 57
yading@11 58 #if CONFIG_WAV_MUXER
yading@11 59 static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen)
yading@11 60 {
yading@11 61 AVDictionaryEntry *tag;
yading@11 62 int len = 0;
yading@11 63
yading@11 64 if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
yading@11 65 len = strlen(tag->value);
yading@11 66 len = FFMIN(len, maxlen);
yading@11 67 avio_write(s->pb, tag->value, len);
yading@11 68 }
yading@11 69
yading@11 70 ffio_fill(s->pb, 0, maxlen - len);
yading@11 71 }
yading@11 72
yading@11 73 static void bwf_write_bext_chunk(AVFormatContext *s)
yading@11 74 {
yading@11 75 AVDictionaryEntry *tmp_tag;
yading@11 76 uint64_t time_reference = 0;
yading@11 77 int64_t bext = ff_start_tag(s->pb, "bext");
yading@11 78
yading@11 79 bwf_write_bext_string(s, "description", 256);
yading@11 80 bwf_write_bext_string(s, "originator", 32);
yading@11 81 bwf_write_bext_string(s, "originator_reference", 32);
yading@11 82 bwf_write_bext_string(s, "origination_date", 10);
yading@11 83 bwf_write_bext_string(s, "origination_time", 8);
yading@11 84
yading@11 85 if (tmp_tag = av_dict_get(s->metadata, "time_reference", NULL, 0))
yading@11 86 time_reference = strtoll(tmp_tag->value, NULL, 10);
yading@11 87 avio_wl64(s->pb, time_reference);
yading@11 88 avio_wl16(s->pb, 1); // set version to 1
yading@11 89
yading@11 90 if (tmp_tag = av_dict_get(s->metadata, "umid", NULL, 0)) {
yading@11 91 unsigned char umidpart_str[17] = {0};
yading@11 92 int i;
yading@11 93 uint64_t umidpart;
yading@11 94 int len = strlen(tmp_tag->value+2);
yading@11 95
yading@11 96 for (i = 0; i < len/16; i++) {
yading@11 97 memcpy(umidpart_str, tmp_tag->value + 2 + (i*16), 16);
yading@11 98 umidpart = strtoll(umidpart_str, NULL, 16);
yading@11 99 avio_wb64(s->pb, umidpart);
yading@11 100 }
yading@11 101 ffio_fill(s->pb, 0, 64 - i*8);
yading@11 102 } else
yading@11 103 ffio_fill(s->pb, 0, 64); // zero UMID
yading@11 104
yading@11 105 ffio_fill(s->pb, 0, 190); // Reserved
yading@11 106
yading@11 107 if (tmp_tag = av_dict_get(s->metadata, "coding_history", NULL, 0))
yading@11 108 avio_put_str(s->pb, tmp_tag->value);
yading@11 109
yading@11 110 ff_end_tag(s->pb, bext);
yading@11 111 }
yading@11 112
yading@11 113 static int wav_write_header(AVFormatContext *s)
yading@11 114 {
yading@11 115 WAVMuxContext *wav = s->priv_data;
yading@11 116 AVIOContext *pb = s->pb;
yading@11 117 int64_t fmt;
yading@11 118
yading@11 119 if (wav->rf64 == RF64_ALWAYS) {
yading@11 120 ffio_wfourcc(pb, "RF64");
yading@11 121 avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */
yading@11 122 } else {
yading@11 123 ffio_wfourcc(pb, "RIFF");
yading@11 124 avio_wl32(pb, 0); /* file length */
yading@11 125 }
yading@11 126
yading@11 127 ffio_wfourcc(pb, "WAVE");
yading@11 128
yading@11 129 if (wav->rf64 != RF64_NEVER) {
yading@11 130 /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */
yading@11 131 ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK");
yading@11 132 avio_wl32(pb, 28); /* chunk size */
yading@11 133 wav->ds64 = avio_tell(pb);
yading@11 134 ffio_fill(pb, 0, 28);
yading@11 135 }
yading@11 136
yading@11 137 /* format header */
yading@11 138 fmt = ff_start_tag(pb, "fmt ");
yading@11 139 if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) {
yading@11 140 av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
yading@11 141 s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE");
yading@11 142 return -1;
yading@11 143 }
yading@11 144 ff_end_tag(pb, fmt);
yading@11 145
yading@11 146 if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */
yading@11 147 && s->pb->seekable) {
yading@11 148 wav->fact_pos = ff_start_tag(pb, "fact");
yading@11 149 avio_wl32(pb, 0);
yading@11 150 ff_end_tag(pb, wav->fact_pos);
yading@11 151 }
yading@11 152
yading@11 153 if (wav->write_bext)
yading@11 154 bwf_write_bext_chunk(s);
yading@11 155
yading@11 156 avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
yading@11 157 wav->maxpts = wav->last_duration = 0;
yading@11 158 wav->minpts = INT64_MAX;
yading@11 159
yading@11 160 /* info header */
yading@11 161 ff_riff_write_info(s);
yading@11 162
yading@11 163 /* data header */
yading@11 164 wav->data = ff_start_tag(pb, "data");
yading@11 165
yading@11 166 avio_flush(pb);
yading@11 167
yading@11 168 return 0;
yading@11 169 }
yading@11 170
yading@11 171 static int wav_write_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 172 {
yading@11 173 AVIOContext *pb = s->pb;
yading@11 174 WAVMuxContext *wav = s->priv_data;
yading@11 175 avio_write(pb, pkt->data, pkt->size);
yading@11 176 if(pkt->pts != AV_NOPTS_VALUE) {
yading@11 177 wav->minpts = FFMIN(wav->minpts, pkt->pts);
yading@11 178 wav->maxpts = FFMAX(wav->maxpts, pkt->pts);
yading@11 179 wav->last_duration = pkt->duration;
yading@11 180 } else
yading@11 181 av_log(s, AV_LOG_ERROR, "wav_write_packet: NOPTS\n");
yading@11 182 return 0;
yading@11 183 }
yading@11 184
yading@11 185 static int wav_write_trailer(AVFormatContext *s)
yading@11 186 {
yading@11 187 AVIOContext *pb = s->pb;
yading@11 188 WAVMuxContext *wav = s->priv_data;
yading@11 189 int64_t file_size, data_size;
yading@11 190 int64_t number_of_samples = 0;
yading@11 191 int rf64 = 0;
yading@11 192
yading@11 193 avio_flush(pb);
yading@11 194
yading@11 195 if (s->pb->seekable) {
yading@11 196 /* update file size */
yading@11 197 file_size = avio_tell(pb);
yading@11 198 data_size = file_size - wav->data;
yading@11 199 if (wav->rf64 == RF64_ALWAYS || (wav->rf64 == RF64_AUTO && file_size - 8 > UINT32_MAX)) {
yading@11 200 rf64 = 1;
yading@11 201 } else {
yading@11 202 avio_seek(pb, 4, SEEK_SET);
yading@11 203 avio_wl32(pb, (uint32_t)(file_size - 8));
yading@11 204 avio_seek(pb, file_size, SEEK_SET);
yading@11 205
yading@11 206 ff_end_tag(pb, wav->data);
yading@11 207 avio_flush(pb);
yading@11 208 }
yading@11 209
yading@11 210 number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
yading@11 211 s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
yading@11 212 s->streams[0]->time_base.den);
yading@11 213
yading@11 214 if(s->streams[0]->codec->codec_tag != 0x01) {
yading@11 215 /* Update num_samps in fact chunk */
yading@11 216 avio_seek(pb, wav->fact_pos, SEEK_SET);
yading@11 217 if (rf64 || (wav->rf64 == RF64_AUTO && number_of_samples > UINT32_MAX)) {
yading@11 218 rf64 = 1;
yading@11 219 avio_wl32(pb, -1);
yading@11 220 } else {
yading@11 221 avio_wl32(pb, number_of_samples);
yading@11 222 avio_seek(pb, file_size, SEEK_SET);
yading@11 223 avio_flush(pb);
yading@11 224 }
yading@11 225 }
yading@11 226
yading@11 227 if (rf64) {
yading@11 228 /* overwrite RIFF with RF64 */
yading@11 229 avio_seek(pb, 0, SEEK_SET);
yading@11 230 ffio_wfourcc(pb, "RF64");
yading@11 231 avio_wl32(pb, -1);
yading@11 232
yading@11 233 /* write ds64 chunk (overwrite JUNK if rf64 == RF64_AUTO) */
yading@11 234 avio_seek(pb, wav->ds64 - 8, SEEK_SET);
yading@11 235 ffio_wfourcc(pb, "ds64");
yading@11 236 avio_wl32(pb, 28); /* ds64 chunk size */
yading@11 237 avio_wl64(pb, file_size - 8); /* RF64 chunk size */
yading@11 238 avio_wl64(pb, data_size); /* data chunk size */
yading@11 239 avio_wl64(pb, number_of_samples); /* fact chunk number of samples */
yading@11 240 avio_wl32(pb, 0); /* number of table entries for non-'data' chunks */
yading@11 241
yading@11 242 /* write -1 in data chunk size */
yading@11 243 avio_seek(pb, wav->data - 4, SEEK_SET);
yading@11 244 avio_wl32(pb, -1);
yading@11 245
yading@11 246 avio_seek(pb, file_size, SEEK_SET);
yading@11 247 avio_flush(pb);
yading@11 248 }
yading@11 249 }
yading@11 250 return 0;
yading@11 251 }
yading@11 252
yading@11 253 #define OFFSET(x) offsetof(WAVMuxContext, x)
yading@11 254 #define ENC AV_OPT_FLAG_ENCODING_PARAM
yading@11 255 static const AVOption options[] = {
yading@11 256 { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
yading@11 257 { "rf64", "Use RF64 header rather than RIFF for large files.", OFFSET(rf64), AV_OPT_TYPE_INT, { .i64 = RF64_NEVER },-1, 1, ENC, "rf64" },
yading@11 258 { "auto", "Write RF64 header if file grows large enough.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_AUTO }, 0, 0, ENC, "rf64" },
yading@11 259 { "always", "Always write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_ALWAYS }, 0, 0, ENC, "rf64" },
yading@11 260 { "never", "Never write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_NEVER }, 0, 0, ENC, "rf64" },
yading@11 261 { NULL },
yading@11 262 };
yading@11 263
yading@11 264 static const AVClass wav_muxer_class = {
yading@11 265 .class_name = "WAV muxer",
yading@11 266 .item_name = av_default_item_name,
yading@11 267 .option = options,
yading@11 268 .version = LIBAVUTIL_VERSION_INT,
yading@11 269 };
yading@11 270
yading@11 271 AVOutputFormat ff_wav_muxer = {
yading@11 272 .name = "wav",
yading@11 273 .long_name = NULL_IF_CONFIG_SMALL("WAV / WAVE (Waveform Audio)"),
yading@11 274 .mime_type = "audio/x-wav",
yading@11 275 .extensions = "wav",
yading@11 276 .priv_data_size = sizeof(WAVMuxContext),
yading@11 277 .audio_codec = AV_CODEC_ID_PCM_S16LE,
yading@11 278 .video_codec = AV_CODEC_ID_NONE,
yading@11 279 .write_header = wav_write_header,
yading@11 280 .write_packet = wav_write_packet,
yading@11 281 .write_trailer = wav_write_trailer,
yading@11 282 .flags = AVFMT_TS_NONSTRICT,
yading@11 283 .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
yading@11 284 .priv_class = &wav_muxer_class,
yading@11 285 };
yading@11 286 #endif /* CONFIG_WAV_MUXER */
yading@11 287
yading@11 288 #if CONFIG_W64_MUXER
yading@11 289 #include "w64.h"
yading@11 290
yading@11 291 static void start_guid(AVIOContext *pb, const uint8_t *guid, int64_t *pos)
yading@11 292 {
yading@11 293 *pos = avio_tell(pb);
yading@11 294
yading@11 295 avio_write(pb, guid, 16);
yading@11 296 avio_wl64(pb, INT64_MAX);
yading@11 297 }
yading@11 298
yading@11 299 static void end_guid(AVIOContext *pb, int64_t start)
yading@11 300 {
yading@11 301 int64_t end, pos = avio_tell(pb);
yading@11 302
yading@11 303 end = FFALIGN(pos, 8);
yading@11 304 ffio_fill(pb, 0, end - pos);
yading@11 305 avio_seek(pb, start + 16, SEEK_SET);
yading@11 306 avio_wl64(pb, end - start);
yading@11 307 avio_seek(pb, end, SEEK_SET);
yading@11 308 }
yading@11 309
yading@11 310 static int w64_write_header(AVFormatContext *s)
yading@11 311 {
yading@11 312 WAVMuxContext *wav = s->priv_data;
yading@11 313 AVIOContext *pb = s->pb;
yading@11 314 int64_t start;
yading@11 315 int ret;
yading@11 316
yading@11 317 avio_write(pb, ff_w64_guid_riff, sizeof(ff_w64_guid_riff));
yading@11 318 avio_wl64(pb, -1);
yading@11 319 avio_write(pb, ff_w64_guid_wave, sizeof(ff_w64_guid_wave));
yading@11 320 start_guid(pb, ff_w64_guid_fmt, &start);
yading@11 321 if ((ret = ff_put_wav_header(pb, s->streams[0]->codec)) < 0) {
yading@11 322 av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
yading@11 323 s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE");
yading@11 324 return ret;
yading@11 325 }
yading@11 326 end_guid(pb, start);
yading@11 327
yading@11 328 if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */
yading@11 329 && s->pb->seekable) {
yading@11 330 start_guid(pb, ff_w64_guid_fact, &wav->fact_pos);
yading@11 331 avio_wl64(pb, 0);
yading@11 332 end_guid(pb, wav->fact_pos);
yading@11 333 }
yading@11 334
yading@11 335 start_guid(pb, ff_w64_guid_data, &wav->data);
yading@11 336
yading@11 337 return 0;
yading@11 338 }
yading@11 339
yading@11 340 static int w64_write_trailer(AVFormatContext *s)
yading@11 341 {
yading@11 342 AVIOContext *pb = s->pb;
yading@11 343 WAVMuxContext *wav = s->priv_data;
yading@11 344 int64_t file_size;
yading@11 345
yading@11 346 if (pb->seekable) {
yading@11 347 end_guid(pb, wav->data);
yading@11 348
yading@11 349 file_size = avio_tell(pb);
yading@11 350 avio_seek(pb, 16, SEEK_SET);
yading@11 351 avio_wl64(pb, file_size);
yading@11 352
yading@11 353 if (s->streams[0]->codec->codec_tag != 0x01) {
yading@11 354 int64_t number_of_samples;
yading@11 355
yading@11 356 number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
yading@11 357 s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
yading@11 358 s->streams[0]->time_base.den);
yading@11 359 avio_seek(pb, wav->fact_pos + 24, SEEK_SET);
yading@11 360 avio_wl64(pb, number_of_samples);
yading@11 361 }
yading@11 362
yading@11 363 avio_seek(pb, file_size, SEEK_SET);
yading@11 364 avio_flush(pb);
yading@11 365 }
yading@11 366
yading@11 367 return 0;
yading@11 368 }
yading@11 369
yading@11 370 AVOutputFormat ff_w64_muxer = {
yading@11 371 .name = "w64",
yading@11 372 .long_name = NULL_IF_CONFIG_SMALL("Sony Wave64"),
yading@11 373 .extensions = "w64",
yading@11 374 .priv_data_size = sizeof(WAVMuxContext),
yading@11 375 .audio_codec = AV_CODEC_ID_PCM_S16LE,
yading@11 376 .video_codec = AV_CODEC_ID_NONE,
yading@11 377 .write_header = w64_write_header,
yading@11 378 .write_packet = wav_write_packet,
yading@11 379 .write_trailer = w64_write_trailer,
yading@11 380 .flags = AVFMT_TS_NONSTRICT,
yading@11 381 .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
yading@11 382 };
yading@11 383 #endif /* CONFIG_W64_MUXER */