1/* 2 * WAV muxer 3 * Copyright (c) 2001, 2002 Fabrice Bellard 4 * 5 * Sony Wave64 muxer 6 * Copyright (c) 2012 Paul B Mahol 7 * 8 * WAV muxer RF64 support 9 * Copyright (c) 2013 Daniel Verkamp <daniel@drv.nu> 10 * 11 * EBU Tech 3285 - Supplement 3 - Peak Envelope Chunk encoder 12 * Copyright (c) 2014 Georg Lippitsch <georg.lippitsch@gmx.at> 13 * 14 * This file is part of FFmpeg. 15 * 16 * FFmpeg is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU Lesser General Public 18 * License as published by the Free Software Foundation; either 19 * version 2.1 of the License, or (at your option) any later version. 20 * 21 * FFmpeg is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 * Lesser General Public License for more details. 25 * 26 * You should have received a copy of the GNU Lesser General Public 27 * License along with FFmpeg; if not, write to the Free Software 28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 29 */ 30 31#include <stdint.h> 32#include <string.h> 33 34#include "libavutil/avstring.h" 35#include "libavutil/dict.h" 36#include "libavutil/common.h" 37#include "libavutil/intreadwrite.h" 38#include "libavutil/mathematics.h" 39#include "libavutil/opt.h" 40#include "libavutil/time.h" 41 42#include "avformat.h" 43#include "avio.h" 44#include "avio_internal.h" 45#include "internal.h" 46#include "riff.h" 47 48#define RF64_AUTO (-1) 49#define RF64_NEVER 0 50#define RF64_ALWAYS 1 51 52#define PEAK_BUFFER_SIZE 1024 53 54typedef enum { 55 PEAK_OFF = 0, 56 PEAK_ON, 57 PEAK_ONLY 58} PeakType; 59 60typedef enum { 61 PEAK_FORMAT_UINT8 = 1, 62 PEAK_FORMAT_UINT16 63} PeakFormat; 64 65typedef struct WAVMuxContext { 66 const AVClass *class; 67 int64_t data; 68 int64_t fact_pos; 69 int64_t ds64; 70 int64_t minpts; 71 int64_t maxpts; 72 int16_t *peak_maxpos, *peak_maxneg; 73 uint32_t peak_num_frames; 74 uint32_t peak_outbuf_size; 75 uint32_t peak_outbuf_bytes; 76 uint32_t peak_pos_pop; 77 uint16_t peak_pop; 78 uint8_t *peak_output; 79 int last_duration; 80 int write_bext; 81 int write_peak; 82 int rf64; 83 int peak_block_size; 84 PeakFormat peak_format; 85 int peak_block_pos; 86 int peak_ppv; 87 int peak_bps; 88} WAVMuxContext; 89 90#if CONFIG_WAV_MUXER 91static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen) 92{ 93 AVDictionaryEntry *tag; 94 int len = 0; 95 96 if (tag = av_dict_get(s->metadata, key, NULL, 0)) { 97 len = strlen(tag->value); 98 len = FFMIN(len, maxlen); 99 avio_write(s->pb, tag->value, len); 100 } 101 102 ffio_fill(s->pb, 0, maxlen - len); 103} 104 105static void bwf_write_bext_chunk(AVFormatContext *s) 106{ 107 AVDictionaryEntry *tmp_tag; 108 uint64_t time_reference = 0; 109 int64_t bext = ff_start_tag(s->pb, "bext"); 110 111 bwf_write_bext_string(s, "description", 256); 112 bwf_write_bext_string(s, "originator", 32); 113 bwf_write_bext_string(s, "originator_reference", 32); 114 bwf_write_bext_string(s, "origination_date", 10); 115 bwf_write_bext_string(s, "origination_time", 8); 116 117 if (tmp_tag = av_dict_get(s->metadata, "time_reference", NULL, 0)) 118 time_reference = strtoll(tmp_tag->value, NULL, 10); 119 avio_wl64(s->pb, time_reference); 120 avio_wl16(s->pb, 1); // set version to 1 121 122 if (tmp_tag = av_dict_get(s->metadata, "umid", NULL, 0)) { 123 unsigned char umidpart_str[17] = {0}; 124 int i; 125 uint64_t umidpart; 126 int len = strlen(tmp_tag->value+2); 127 128 for (i = 0; i < len/16; i++) { 129 memcpy(umidpart_str, tmp_tag->value + 2 + (i*16), 16); 130 umidpart = strtoll(umidpart_str, NULL, 16); 131 avio_wb64(s->pb, umidpart); 132 } 133 ffio_fill(s->pb, 0, 64 - i*8); 134 } else 135 ffio_fill(s->pb, 0, 64); // zero UMID 136 137 ffio_fill(s->pb, 0, 190); // Reserved 138 139 if (tmp_tag = av_dict_get(s->metadata, "coding_history", NULL, 0)) 140 avio_put_str(s->pb, tmp_tag->value); 141 142 ff_end_tag(s->pb, bext); 143} 144 145static av_cold void peak_free_buffers(AVFormatContext *s) 146{ 147 WAVMuxContext *wav = s->priv_data; 148 149 av_freep(&wav->peak_maxpos); 150 av_freep(&wav->peak_maxneg); 151 av_freep(&wav->peak_output); 152} 153 154static av_cold int peak_init_writer(AVFormatContext *s) 155{ 156 WAVMuxContext *wav = s->priv_data; 157 AVCodecContext *enc = s->streams[0]->codec; 158 159 if (enc->codec_id != AV_CODEC_ID_PCM_S8 && 160 enc->codec_id != AV_CODEC_ID_PCM_S16LE && 161 enc->codec_id != AV_CODEC_ID_PCM_U8 && 162 enc->codec_id != AV_CODEC_ID_PCM_U16LE) { 163 av_log(s, AV_LOG_ERROR, "%s codec not supported for Peak Chunk\n", 164 s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE"); 165 return -1; 166 } 167 168 wav->peak_bps = av_get_bits_per_sample(enc->codec_id) / 8; 169 170 if (wav->peak_bps == 1 && wav->peak_format == PEAK_FORMAT_UINT16) { 171 av_log(s, AV_LOG_ERROR, 172 "Writing 16 bit peak for 8 bit audio does not make sense\n"); 173 return AVERROR(EINVAL); 174 } 175 176 wav->peak_maxpos = av_mallocz_array(enc->channels, sizeof(*wav->peak_maxpos)); 177 wav->peak_maxneg = av_mallocz_array(enc->channels, sizeof(*wav->peak_maxneg)); 178 wav->peak_output = av_malloc(PEAK_BUFFER_SIZE); 179 if (!wav->peak_maxpos || !wav->peak_maxneg || !wav->peak_output) 180 goto nomem; 181 182 wav->peak_outbuf_size = PEAK_BUFFER_SIZE; 183 184 return 0; 185 186nomem: 187 av_log(s, AV_LOG_ERROR, "Out of memory\n"); 188 peak_free_buffers(s); 189 return AVERROR(ENOMEM); 190} 191 192static void peak_write_frame(AVFormatContext *s) 193{ 194 WAVMuxContext *wav = s->priv_data; 195 AVCodecContext *enc = s->streams[0]->codec; 196 int peak_of_peaks; 197 int c; 198 199 if (!wav->peak_output) 200 return; 201 202 for (c = 0; c < enc->channels; c++) { 203 wav->peak_maxneg[c] = -wav->peak_maxneg[c]; 204 205 if (wav->peak_bps == 2 && wav->peak_format == PEAK_FORMAT_UINT8) { 206 wav->peak_maxpos[c] = wav->peak_maxpos[c] / 256; 207 wav->peak_maxneg[c] = wav->peak_maxneg[c] / 256; 208 } 209 210 if (wav->peak_ppv == 1) 211 wav->peak_maxpos[c] = 212 FFMAX(wav->peak_maxpos[c], wav->peak_maxneg[c]); 213 214 peak_of_peaks = FFMAX3(wav->peak_maxpos[c], wav->peak_maxneg[c], 215 wav->peak_pop); 216 if (peak_of_peaks > wav->peak_pop) 217 wav->peak_pos_pop = wav->peak_num_frames; 218 wav->peak_pop = peak_of_peaks; 219 220 if (wav->peak_outbuf_size - wav->peak_outbuf_bytes < 221 wav->peak_format * wav->peak_ppv) { 222 wav->peak_outbuf_size += PEAK_BUFFER_SIZE; 223 wav->peak_output = av_realloc(wav->peak_output, 224 wav->peak_outbuf_size); 225 if (!wav->peak_output) { 226 av_log(s, AV_LOG_ERROR, "No memory for peak data\n"); 227 return; 228 } 229 } 230 231 if (wav->peak_format == PEAK_FORMAT_UINT8) { 232 wav->peak_output[wav->peak_outbuf_bytes++] = 233 wav->peak_maxpos[c]; 234 if (wav->peak_ppv == 2) { 235 wav->peak_output[wav->peak_outbuf_bytes++] = 236 wav->peak_maxneg[c]; 237 } 238 } else { 239 AV_WL16(wav->peak_output + wav->peak_outbuf_bytes, 240 wav->peak_maxpos[c]); 241 wav->peak_outbuf_bytes += 2; 242 if (wav->peak_ppv == 2) { 243 AV_WL16(wav->peak_output + wav->peak_outbuf_bytes, 244 wav->peak_maxneg[c]); 245 wav->peak_outbuf_bytes += 2; 246 } 247 } 248 wav->peak_maxpos[c] = 0; 249 wav->peak_maxneg[c] = 0; 250 } 251 wav->peak_num_frames++; 252} 253 254static void peak_write_chunk(AVFormatContext *s) 255{ 256 WAVMuxContext *wav = s->priv_data; 257 AVIOContext *pb = s->pb; 258 AVCodecContext *enc = s->streams[0]->codec; 259 int64_t peak = ff_start_tag(s->pb, "levl"); 260 int64_t now0; 261 time_t now_secs; 262 char timestamp[28]; 263 264 /* Peak frame of incomplete block at end */ 265 if (wav->peak_block_pos) 266 peak_write_frame(s); 267 268 memset(timestamp, 0, sizeof(timestamp)); 269 if (!(s->flags & AVFMT_FLAG_BITEXACT)) { 270 av_log(s, AV_LOG_INFO, "Writing local time and date to Peak Envelope Chunk\n"); 271 now0 = av_gettime(); 272 now_secs = now0 / 1000000; 273 strftime(timestamp, sizeof(timestamp), "%Y:%m:%d:%H:%M:%S:", localtime(&now_secs)); 274 av_strlcatf(timestamp, sizeof(timestamp), "%03d", (int)((now0 / 1000) % 1000)); 275 } 276 277 avio_wl32(pb, 1); /* version */ 278 avio_wl32(pb, wav->peak_format); /* 8 or 16 bit */ 279 avio_wl32(pb, wav->peak_ppv); /* positive and negative */ 280 avio_wl32(pb, wav->peak_block_size); /* frames per value */ 281 avio_wl32(pb, enc->channels); /* number of channels */ 282 avio_wl32(pb, wav->peak_num_frames); /* number of peak frames */ 283 avio_wl32(pb, wav->peak_pos_pop); /* audio sample frame index */ 284 avio_wl32(pb, 128); /* equal to size of header */ 285 avio_write(pb, timestamp, 28); /* ASCII time stamp */ 286 ffio_fill(pb, 0, 60); 287 288 avio_write(pb, wav->peak_output, wav->peak_outbuf_bytes); 289 290 ff_end_tag(pb, peak); 291 292 if (!wav->data) 293 wav->data = peak; 294} 295 296static int wav_write_header(AVFormatContext *s) 297{ 298 WAVMuxContext *wav = s->priv_data; 299 AVIOContext *pb = s->pb; 300 int64_t fmt; 301 302 if (s->nb_streams != 1) { 303 av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n"); 304 return AVERROR(EINVAL); 305 } 306 307 if (wav->rf64 == RF64_ALWAYS) { 308 ffio_wfourcc(pb, "RF64"); 309 avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */ 310 } else { 311 ffio_wfourcc(pb, "RIFF"); 312 avio_wl32(pb, -1); /* file length */ 313 } 314 315 ffio_wfourcc(pb, "WAVE"); 316 317 if (wav->rf64 != RF64_NEVER) { 318 /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */ 319 ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK"); 320 avio_wl32(pb, 28); /* chunk size */ 321 wav->ds64 = avio_tell(pb); 322 ffio_fill(pb, 0, 28); 323 } 324 325 if (wav->write_peak != 2) { 326 /* format header */ 327 fmt = ff_start_tag(pb, "fmt "); 328 if (ff_put_wav_header(pb, s->streams[0]->codec, 0) < 0) { 329 const AVCodecDescriptor *desc = avcodec_descriptor_get(s->streams[0]->codec->codec_id); 330 av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n", 331 desc ? desc->name : "unknown"); 332 return AVERROR(ENOSYS); 333 } 334 ff_end_tag(pb, fmt); 335 } 336 337 if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */ 338 && s->pb->seekable) { 339 wav->fact_pos = ff_start_tag(pb, "fact"); 340 avio_wl32(pb, 0); 341 ff_end_tag(pb, wav->fact_pos); 342 } 343 344 if (wav->write_bext) 345 bwf_write_bext_chunk(s); 346 347 if (wav->write_peak) { 348 int ret; 349 if ((ret = peak_init_writer(s)) < 0) 350 return ret; 351 } 352 353 avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); 354 wav->maxpts = wav->last_duration = 0; 355 wav->minpts = INT64_MAX; 356 357 if (wav->write_peak != 2) { 358 /* info header */ 359 ff_riff_write_info(s); 360 361 /* data header */ 362 wav->data = ff_start_tag(pb, "data"); 363 } 364 365 avio_flush(pb); 366 367 return 0; 368} 369 370static int wav_write_packet(AVFormatContext *s, AVPacket *pkt) 371{ 372 AVIOContext *pb = s->pb; 373 WAVMuxContext *wav = s->priv_data; 374 375 if (wav->write_peak != 2) 376 avio_write(pb, pkt->data, pkt->size); 377 378 if (wav->write_peak) { 379 int c = 0; 380 int i; 381 for (i = 0; i < pkt->size; i += wav->peak_bps) { 382 if (wav->peak_bps == 1) { 383 wav->peak_maxpos[c] = FFMAX(wav->peak_maxpos[c], *(int8_t*)(pkt->data + i)); 384 wav->peak_maxneg[c] = FFMIN(wav->peak_maxneg[c], *(int8_t*)(pkt->data + i)); 385 } else { 386 wav->peak_maxpos[c] = FFMAX(wav->peak_maxpos[c], (int16_t)AV_RL16(pkt->data + i)); 387 wav->peak_maxneg[c] = FFMIN(wav->peak_maxneg[c], (int16_t)AV_RL16(pkt->data + i)); 388 } 389 if (++c == s->streams[0]->codec->channels) { 390 c = 0; 391 if (++wav->peak_block_pos == wav->peak_block_size) { 392 peak_write_frame(s); 393 wav->peak_block_pos = 0; 394 } 395 } 396 } 397 } 398 399 if(pkt->pts != AV_NOPTS_VALUE) { 400 wav->minpts = FFMIN(wav->minpts, pkt->pts); 401 wav->maxpts = FFMAX(wav->maxpts, pkt->pts); 402 wav->last_duration = pkt->duration; 403 } else 404 av_log(s, AV_LOG_ERROR, "wav_write_packet: NOPTS\n"); 405 return 0; 406} 407 408static int wav_write_trailer(AVFormatContext *s) 409{ 410 AVIOContext *pb = s->pb; 411 WAVMuxContext *wav = s->priv_data; 412 int64_t file_size, data_size; 413 int64_t number_of_samples = 0; 414 int rf64 = 0; 415 416 avio_flush(pb); 417 418 if (s->pb->seekable) { 419 if (wav->write_peak != 2) { 420 ff_end_tag(pb, wav->data); 421 avio_flush(pb); 422 } 423 424 if (wav->write_peak && wav->peak_output) { 425 peak_write_chunk(s); 426 avio_flush(pb); 427 } 428 429 /* update file size */ 430 file_size = avio_tell(pb); 431 data_size = file_size - wav->data; 432 if (wav->rf64 == RF64_ALWAYS || (wav->rf64 == RF64_AUTO && file_size - 8 > UINT32_MAX)) { 433 rf64 = 1; 434 } else { 435 avio_seek(pb, 4, SEEK_SET); 436 avio_wl32(pb, (uint32_t)(file_size - 8)); 437 avio_seek(pb, file_size, SEEK_SET); 438 439 avio_flush(pb); 440 } 441 442 number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration, 443 s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num, 444 s->streams[0]->time_base.den); 445 446 if(s->streams[0]->codec->codec_tag != 0x01) { 447 /* Update num_samps in fact chunk */ 448 avio_seek(pb, wav->fact_pos, SEEK_SET); 449 if (rf64 || (wav->rf64 == RF64_AUTO && number_of_samples > UINT32_MAX)) { 450 rf64 = 1; 451 avio_wl32(pb, -1); 452 } else { 453 avio_wl32(pb, number_of_samples); 454 avio_seek(pb, file_size, SEEK_SET); 455 avio_flush(pb); 456 } 457 } 458 459 if (rf64) { 460 /* overwrite RIFF with RF64 */ 461 avio_seek(pb, 0, SEEK_SET); 462 ffio_wfourcc(pb, "RF64"); 463 avio_wl32(pb, -1); 464 465 /* write ds64 chunk (overwrite JUNK if rf64 == RF64_AUTO) */ 466 avio_seek(pb, wav->ds64 - 8, SEEK_SET); 467 ffio_wfourcc(pb, "ds64"); 468 avio_wl32(pb, 28); /* ds64 chunk size */ 469 avio_wl64(pb, file_size - 8); /* RF64 chunk size */ 470 avio_wl64(pb, data_size); /* data chunk size */ 471 avio_wl64(pb, number_of_samples); /* fact chunk number of samples */ 472 avio_wl32(pb, 0); /* number of table entries for non-'data' chunks */ 473 474 /* write -1 in data chunk size */ 475 avio_seek(pb, wav->data - 4, SEEK_SET); 476 avio_wl32(pb, -1); 477 478 avio_seek(pb, file_size, SEEK_SET); 479 avio_flush(pb); 480 } 481 } 482 483 if (wav->write_peak) 484 peak_free_buffers(s); 485 486 return 0; 487} 488 489#define OFFSET(x) offsetof(WAVMuxContext, x) 490#define ENC AV_OPT_FLAG_ENCODING_PARAM 491static const AVOption options[] = { 492 { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC }, 493 { "write_peak", "Write Peak Envelope chunk.", OFFSET(write_peak), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, ENC, "peak" }, 494 { "off", "Do not write peak chunk.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_OFF }, 0, 0, ENC, "peak" }, 495 { "on", "Append peak chunk after wav data.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_ON }, 0, 0, ENC, "peak" }, 496 { "only", "Write only peak chunk, omit wav data.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_ONLY }, 0, 0, ENC, "peak" }, 497 { "rf64", "Use RF64 header rather than RIFF for large files.", OFFSET(rf64), AV_OPT_TYPE_INT, { .i64 = RF64_NEVER },-1, 1, ENC, "rf64" }, 498 { "auto", "Write RF64 header if file grows large enough.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_AUTO }, 0, 0, ENC, "rf64" }, 499 { "always", "Always write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_ALWAYS }, 0, 0, ENC, "rf64" }, 500 { "never", "Never write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_NEVER }, 0, 0, ENC, "rf64" }, 501 { "peak_block_size", "Number of audio samples used to generate each peak frame.", OFFSET(peak_block_size), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, 65536, ENC }, 502 { "peak_format", "The format of the peak envelope data (1: uint8, 2: uint16).", OFFSET(peak_format), AV_OPT_TYPE_INT, { .i64 = PEAK_FORMAT_UINT16 }, PEAK_FORMAT_UINT8, PEAK_FORMAT_UINT16, ENC }, 503 { "peak_ppv", "Number of peak points per peak value (1 or 2).", OFFSET(peak_ppv), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 2, ENC }, 504 { NULL }, 505}; 506 507static const AVClass wav_muxer_class = { 508 .class_name = "WAV muxer", 509 .item_name = av_default_item_name, 510 .option = options, 511 .version = LIBAVUTIL_VERSION_INT, 512}; 513 514AVOutputFormat ff_wav_muxer = { 515 .name = "wav", 516 .long_name = NULL_IF_CONFIG_SMALL("WAV / WAVE (Waveform Audio)"), 517 .mime_type = "audio/x-wav", 518 .extensions = "wav", 519 .priv_data_size = sizeof(WAVMuxContext), 520 .audio_codec = AV_CODEC_ID_PCM_S16LE, 521 .video_codec = AV_CODEC_ID_NONE, 522 .write_header = wav_write_header, 523 .write_packet = wav_write_packet, 524 .write_trailer = wav_write_trailer, 525 .flags = AVFMT_TS_NONSTRICT, 526 .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 }, 527 .priv_class = &wav_muxer_class, 528}; 529#endif /* CONFIG_WAV_MUXER */ 530 531#if CONFIG_W64_MUXER 532#include "w64.h" 533 534static void start_guid(AVIOContext *pb, const uint8_t *guid, int64_t *pos) 535{ 536 *pos = avio_tell(pb); 537 538 avio_write(pb, guid, 16); 539 avio_wl64(pb, INT64_MAX); 540} 541 542static void end_guid(AVIOContext *pb, int64_t start) 543{ 544 int64_t end, pos = avio_tell(pb); 545 546 end = FFALIGN(pos, 8); 547 ffio_fill(pb, 0, end - pos); 548 avio_seek(pb, start + 16, SEEK_SET); 549 avio_wl64(pb, end - start); 550 avio_seek(pb, end, SEEK_SET); 551} 552 553static int w64_write_header(AVFormatContext *s) 554{ 555 WAVMuxContext *wav = s->priv_data; 556 AVIOContext *pb = s->pb; 557 int64_t start; 558 int ret; 559 560 avio_write(pb, ff_w64_guid_riff, sizeof(ff_w64_guid_riff)); 561 avio_wl64(pb, -1); 562 avio_write(pb, ff_w64_guid_wave, sizeof(ff_w64_guid_wave)); 563 start_guid(pb, ff_w64_guid_fmt, &start); 564 if ((ret = ff_put_wav_header(pb, s->streams[0]->codec, 0)) < 0) { 565 av_log(s, AV_LOG_ERROR, "%s codec not supported\n", 566 s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE"); 567 return ret; 568 } 569 end_guid(pb, start); 570 571 if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */ 572 && s->pb->seekable) { 573 start_guid(pb, ff_w64_guid_fact, &wav->fact_pos); 574 avio_wl64(pb, 0); 575 end_guid(pb, wav->fact_pos); 576 } 577 578 start_guid(pb, ff_w64_guid_data, &wav->data); 579 580 return 0; 581} 582 583static int w64_write_trailer(AVFormatContext *s) 584{ 585 AVIOContext *pb = s->pb; 586 WAVMuxContext *wav = s->priv_data; 587 int64_t file_size; 588 589 if (pb->seekable) { 590 end_guid(pb, wav->data); 591 592 file_size = avio_tell(pb); 593 avio_seek(pb, 16, SEEK_SET); 594 avio_wl64(pb, file_size); 595 596 if (s->streams[0]->codec->codec_tag != 0x01) { 597 int64_t number_of_samples; 598 599 number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration, 600 s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num, 601 s->streams[0]->time_base.den); 602 avio_seek(pb, wav->fact_pos + 24, SEEK_SET); 603 avio_wl64(pb, number_of_samples); 604 } 605 606 avio_seek(pb, file_size, SEEK_SET); 607 avio_flush(pb); 608 } 609 610 return 0; 611} 612 613AVOutputFormat ff_w64_muxer = { 614 .name = "w64", 615 .long_name = NULL_IF_CONFIG_SMALL("Sony Wave64"), 616 .extensions = "w64", 617 .priv_data_size = sizeof(WAVMuxContext), 618 .audio_codec = AV_CODEC_ID_PCM_S16LE, 619 .video_codec = AV_CODEC_ID_NONE, 620 .write_header = w64_write_header, 621 .write_packet = wav_write_packet, 622 .write_trailer = w64_write_trailer, 623 .flags = AVFMT_TS_NONSTRICT, 624 .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 }, 625}; 626#endif /* CONFIG_W64_MUXER */ 627