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 "config_components.h" 32 33#include <stdint.h> 34#include <string.h> 35 36#include "libavutil/avstring.h" 37#include "libavutil/dict.h" 38#include "libavutil/common.h" 39#include "libavutil/intreadwrite.h" 40#include "libavutil/mathematics.h" 41#include "libavutil/opt.h" 42#include "libavutil/time.h" 43#include "libavutil/time_internal.h" 44 45#include "avformat.h" 46#include "avio.h" 47#include "avio_internal.h" 48#include "internal.h" 49#include "riff.h" 50 51#define RF64_AUTO (-1) 52#define RF64_NEVER 0 53#define RF64_ALWAYS 1 54 55typedef enum { 56 PEAK_OFF = 0, 57 PEAK_ON, 58 PEAK_ONLY 59} PeakType; 60 61typedef enum { 62 PEAK_FORMAT_UINT8 = 1, 63 PEAK_FORMAT_UINT16 64} PeakFormat; 65 66typedef struct WAVMuxContext { 67 const AVClass *class; 68 int64_t data; 69 int64_t fact_pos; 70 int64_t ds64; 71 int64_t minpts; 72 int64_t maxpts; 73 int16_t *peak_maxpos, *peak_maxneg; 74 uint32_t peak_num_frames; 75 unsigned peak_outbuf_size; 76 uint32_t peak_outbuf_bytes; 77 unsigned size_increment; 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 int 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 size_t 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)) && strlen(tmp_tag->value) > 2) { 123 unsigned char umidpart_str[17] = {0}; 124 int64_t i; 125 uint64_t umidpart; 126 size_t 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 wav_deinit(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 AVCodecParameters *par = s->streams[0]->codecpar; 158 159 if (par->codec_id != AV_CODEC_ID_PCM_S8 && 160 par->codec_id != AV_CODEC_ID_PCM_S16LE && 161 par->codec_id != AV_CODEC_ID_PCM_U8 && 162 par->codec_id != AV_CODEC_ID_PCM_U16LE) { 163 av_log(s, AV_LOG_ERROR, "Codec %s not supported for Peak Chunk\n", 164 avcodec_get_name(par->codec_id)); 165 return -1; 166 } 167 168 wav->peak_bps = av_get_bits_per_sample(par->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 if (par->ch_layout.nb_channels > INT_MAX / (wav->peak_bps * wav->peak_ppv)) 176 return AVERROR(ERANGE); 177 wav->size_increment = par->ch_layout.nb_channels * wav->peak_bps * wav->peak_ppv; 178 179 wav->peak_maxpos = av_calloc(par->ch_layout.nb_channels, sizeof(*wav->peak_maxpos)); 180 wav->peak_maxneg = av_calloc(par->ch_layout.nb_channels, sizeof(*wav->peak_maxneg)); 181 if (!wav->peak_maxpos || !wav->peak_maxneg) 182 goto nomem; 183 184 return 0; 185 186nomem: 187 av_log(s, AV_LOG_ERROR, "Out of memory\n"); 188 return AVERROR(ENOMEM); 189} 190 191static int peak_write_frame(AVFormatContext *s) 192{ 193 WAVMuxContext *wav = s->priv_data; 194 AVCodecParameters *par = s->streams[0]->codecpar; 195 unsigned new_size = wav->peak_outbuf_bytes + wav->size_increment; 196 uint8_t *tmp; 197 int c; 198 199 if (new_size > INT_MAX) { 200 wav->write_peak = PEAK_OFF; 201 return AVERROR(ERANGE); 202 } 203 tmp = av_fast_realloc(wav->peak_output, &wav->peak_outbuf_size, new_size); 204 if (!tmp) { 205 wav->write_peak = PEAK_OFF; 206 return AVERROR(ENOMEM); 207 } 208 wav->peak_output = tmp; 209 210 for (c = 0; c < par->ch_layout.nb_channels; c++) { 211 wav->peak_maxneg[c] = -wav->peak_maxneg[c]; 212 213 if (wav->peak_bps == 2 && wav->peak_format == PEAK_FORMAT_UINT8) { 214 wav->peak_maxpos[c] = wav->peak_maxpos[c] / 256; 215 wav->peak_maxneg[c] = wav->peak_maxneg[c] / 256; 216 } 217 218 if (wav->peak_ppv == 1) 219 wav->peak_maxpos[c] = 220 FFMAX(wav->peak_maxpos[c], wav->peak_maxneg[c]); 221 222 if (wav->peak_format == PEAK_FORMAT_UINT8) { 223 wav->peak_output[wav->peak_outbuf_bytes++] = 224 wav->peak_maxpos[c]; 225 if (wav->peak_ppv == 2) { 226 wav->peak_output[wav->peak_outbuf_bytes++] = 227 wav->peak_maxneg[c]; 228 } 229 } else { 230 AV_WL16(wav->peak_output + wav->peak_outbuf_bytes, 231 wav->peak_maxpos[c]); 232 wav->peak_outbuf_bytes += 2; 233 if (wav->peak_ppv == 2) { 234 AV_WL16(wav->peak_output + wav->peak_outbuf_bytes, 235 wav->peak_maxneg[c]); 236 wav->peak_outbuf_bytes += 2; 237 } 238 } 239 wav->peak_maxpos[c] = 0; 240 wav->peak_maxneg[c] = 0; 241 } 242 wav->peak_num_frames++; 243 244 return 0; 245} 246 247static int peak_write_chunk(AVFormatContext *s) 248{ 249 WAVMuxContext *wav = s->priv_data; 250 AVIOContext *pb = s->pb; 251 AVCodecParameters *par = s->streams[0]->codecpar; 252 int64_t peak = ff_start_tag(s->pb, "levl"); 253 int64_t now0; 254 time_t now_secs; 255 char timestamp[28]; 256 257 /* Peak frame of incomplete block at end */ 258 if (wav->peak_block_pos) { 259 int ret = peak_write_frame(s); 260 if (ret < 0) 261 return ret; 262 } 263 264 memset(timestamp, 0, sizeof(timestamp)); 265 if (!(s->flags & AVFMT_FLAG_BITEXACT)) { 266 struct tm tmpbuf; 267 av_log(s, AV_LOG_INFO, "Writing local time and date to Peak Envelope Chunk\n"); 268 now0 = av_gettime(); 269 now_secs = now0 / 1000000; 270 if (strftime(timestamp, sizeof(timestamp), "%Y:%m:%d:%H:%M:%S:", localtime_r(&now_secs, &tmpbuf))) { 271 av_strlcatf(timestamp, sizeof(timestamp), "%03d", (int)((now0 / 1000) % 1000)); 272 } else { 273 av_log(s, AV_LOG_ERROR, "Failed to write timestamp\n"); 274 return -1; 275 } 276 } 277 278 avio_wl32(pb, 1); /* version */ 279 avio_wl32(pb, wav->peak_format); /* 8 or 16 bit */ 280 avio_wl32(pb, wav->peak_ppv); /* positive and negative */ 281 avio_wl32(pb, wav->peak_block_size); /* frames per value */ 282 avio_wl32(pb, par->ch_layout.nb_channels); /* number of channels */ 283 avio_wl32(pb, wav->peak_num_frames); /* number of peak frames */ 284 avio_wl32(pb, -1); /* audio sample frame position (not implemented) */ 285 avio_wl32(pb, 128); /* equal to size of header */ 286 avio_write(pb, timestamp, 28); /* ASCII time stamp */ 287 ffio_fill(pb, 0, 60); 288 289 avio_write(pb, wav->peak_output, wav->peak_outbuf_bytes); 290 291 ff_end_tag(pb, peak); 292 293 if (!wav->data) 294 wav->data = peak; 295 296 return 0; 297} 298 299static int wav_write_header(AVFormatContext *s) 300{ 301 WAVMuxContext *wav = s->priv_data; 302 AVIOContext *pb = s->pb; 303 int64_t fmt; 304 305 if (s->nb_streams != 1) { 306 av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n"); 307 return AVERROR(EINVAL); 308 } 309 310 if (wav->rf64 == RF64_ALWAYS) { 311 ffio_wfourcc(pb, "RF64"); 312 avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */ 313 } else { 314 ffio_wfourcc(pb, "RIFF"); 315 avio_wl32(pb, -1); /* file length */ 316 } 317 318 ffio_wfourcc(pb, "WAVE"); 319 320 if (wav->rf64 != RF64_NEVER) { 321 /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */ 322 ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK"); 323 avio_wl32(pb, 28); /* chunk size */ 324 wav->ds64 = avio_tell(pb); 325 ffio_fill(pb, 0, 28); 326 } 327 328 if (wav->write_peak != PEAK_ONLY) { 329 /* format header */ 330 fmt = ff_start_tag(pb, "fmt "); 331 if (ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0) < 0) { 332 av_log(s, AV_LOG_ERROR, "Codec %s not supported in WAVE format\n", 333 avcodec_get_name(s->streams[0]->codecpar->codec_id)); 334 return AVERROR(ENOSYS); 335 } 336 ff_end_tag(pb, fmt); 337 } 338 339 if (s->streams[0]->codecpar->codec_tag != 0x01 /* hence for all other than PCM */ 340 && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { 341 wav->fact_pos = ff_start_tag(pb, "fact"); 342 avio_wl32(pb, 0); 343 ff_end_tag(pb, wav->fact_pos); 344 } 345 346 if (wav->write_bext) 347 bwf_write_bext_chunk(s); 348 349 if (wav->write_peak) { 350 int ret; 351 if ((ret = peak_init_writer(s)) < 0) 352 return ret; 353 } 354 355 avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codecpar->sample_rate); 356 wav->maxpts = wav->last_duration = 0; 357 wav->minpts = INT64_MAX; 358 359 if (wav->write_peak != PEAK_ONLY) { 360 /* info header */ 361 ff_riff_write_info(s); 362 363 /* data header */ 364 wav->data = ff_start_tag(pb, "data"); 365 } 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 != PEAK_ONLY) 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]->codecpar->ch_layout.nb_channels) { 390 c = 0; 391 if (++wav->peak_block_pos == wav->peak_block_size) { 392 int ret = peak_write_frame(s); 393 if (ret < 0) 394 return ret; 395 wav->peak_block_pos = 0; 396 } 397 } 398 } 399 } 400 401 if(pkt->pts != AV_NOPTS_VALUE) { 402 wav->minpts = FFMIN(wav->minpts, pkt->pts); 403 wav->maxpts = FFMAX(wav->maxpts, pkt->pts); 404 wav->last_duration = pkt->duration; 405 } else 406 av_log(s, AV_LOG_ERROR, "wav_write_packet: NOPTS\n"); 407 return 0; 408} 409 410static int wav_write_trailer(AVFormatContext *s) 411{ 412 AVIOContext *pb = s->pb; 413 WAVMuxContext *wav = s->priv_data; 414 int64_t file_size, data_size; 415 int64_t number_of_samples = 0; 416 int rf64 = 0; 417 int ret = 0; 418 419 if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { 420 if (wav->write_peak != PEAK_ONLY && avio_tell(pb) - wav->data < UINT32_MAX) { 421 ff_end_tag(pb, wav->data); 422 } 423 424 if (wav->write_peak && wav->peak_output) { 425 ret = peak_write_chunk(s); 426 } 427 428 /* update file size */ 429 file_size = avio_tell(pb); 430 data_size = file_size - wav->data; 431 if (wav->rf64 == RF64_ALWAYS || (wav->rf64 == RF64_AUTO && file_size - 8 > UINT32_MAX)) { 432 rf64 = 1; 433 } else if (file_size - 8 <= UINT32_MAX) { 434 avio_seek(pb, 4, SEEK_SET); 435 avio_wl32(pb, (uint32_t)(file_size - 8)); 436 avio_seek(pb, file_size, SEEK_SET); 437 } else { 438 av_log(s, AV_LOG_ERROR, 439 "Filesize %"PRId64" invalid for wav, output file will be broken\n", 440 file_size); 441 } 442 number_of_samples = av_rescale_q(wav->maxpts - wav->minpts + wav->last_duration, 443 s->streams[0]->time_base, 444 av_make_q(1, s->streams[0]->codecpar->sample_rate)); 445 446 if(s->streams[0]->codecpar->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 } 456 } 457 458 if (rf64) { 459 /* overwrite RIFF with RF64 */ 460 avio_seek(pb, 0, SEEK_SET); 461 ffio_wfourcc(pb, "RF64"); 462 avio_wl32(pb, -1); 463 464 /* write ds64 chunk (overwrite JUNK if rf64 == RF64_AUTO) */ 465 avio_seek(pb, wav->ds64 - 8, SEEK_SET); 466 ffio_wfourcc(pb, "ds64"); 467 avio_wl32(pb, 28); /* ds64 chunk size */ 468 avio_wl64(pb, file_size - 8); /* RF64 chunk size */ 469 avio_wl64(pb, data_size); /* data chunk size */ 470 avio_wl64(pb, number_of_samples); /* fact chunk number of samples */ 471 avio_wl32(pb, 0); /* number of table entries for non-'data' chunks */ 472 473 /* write -1 in data chunk size */ 474 avio_seek(pb, wav->data - 4, SEEK_SET); 475 avio_wl32(pb, -1); 476 477 avio_seek(pb, file_size, SEEK_SET); 478 } 479 } 480 481 return ret; 482} 483 484#define OFFSET(x) offsetof(WAVMuxContext, x) 485#define ENC AV_OPT_FLAG_ENCODING_PARAM 486static const AVOption options[] = { 487 { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, 488 { "write_peak", "Write Peak Envelope chunk.", OFFSET(write_peak), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, ENC, "peak" }, 489 { "off", "Do not write peak chunk.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_OFF }, 0, 0, ENC, "peak" }, 490 { "on", "Append peak chunk after wav data.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_ON }, 0, 0, ENC, "peak" }, 491 { "only", "Write only peak chunk, omit wav data.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_ONLY }, 0, 0, ENC, "peak" }, 492 { "rf64", "Use RF64 header rather than RIFF for large files.", OFFSET(rf64), AV_OPT_TYPE_INT, { .i64 = RF64_NEVER },-1, 1, ENC, "rf64" }, 493 { "auto", "Write RF64 header if file grows large enough.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_AUTO }, 0, 0, ENC, "rf64" }, 494 { "always", "Always write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_ALWAYS }, 0, 0, ENC, "rf64" }, 495 { "never", "Never write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_NEVER }, 0, 0, ENC, "rf64" }, 496 { "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 }, 497 { "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 }, 498 { "peak_ppv", "Number of peak points per peak value (1 or 2).", OFFSET(peak_ppv), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 2, ENC }, 499 { NULL }, 500}; 501 502static const AVClass wav_muxer_class = { 503 .class_name = "WAV muxer", 504 .item_name = av_default_item_name, 505 .option = options, 506 .version = LIBAVUTIL_VERSION_INT, 507}; 508 509const AVOutputFormat ff_wav_muxer = { 510 .name = "wav", 511 .long_name = NULL_IF_CONFIG_SMALL("WAV / WAVE (Waveform Audio)"), 512 .mime_type = "audio/x-wav", 513 .extensions = "wav", 514 .priv_data_size = sizeof(WAVMuxContext), 515 .audio_codec = AV_CODEC_ID_PCM_S16LE, 516 .video_codec = AV_CODEC_ID_NONE, 517 .write_header = wav_write_header, 518 .write_packet = wav_write_packet, 519 .write_trailer = wav_write_trailer, 520 .deinit = wav_deinit, 521 .flags = AVFMT_TS_NONSTRICT, 522 .codec_tag = ff_wav_codec_tags_list, 523 .priv_class = &wav_muxer_class, 524}; 525#endif /* CONFIG_WAV_MUXER */ 526 527#if CONFIG_W64_MUXER 528#include "w64.h" 529 530static void start_guid(AVIOContext *pb, const uint8_t *guid, int64_t *pos) 531{ 532 *pos = avio_tell(pb); 533 534 avio_write(pb, guid, 16); 535 avio_wl64(pb, INT64_MAX); 536} 537 538static void end_guid(AVIOContext *pb, int64_t start) 539{ 540 int64_t end, pos = avio_tell(pb); 541 542 end = FFALIGN(pos, 8); 543 ffio_fill(pb, 0, end - pos); 544 avio_seek(pb, start + 16, SEEK_SET); 545 avio_wl64(pb, end - start); 546 avio_seek(pb, end, SEEK_SET); 547} 548 549static int w64_write_header(AVFormatContext *s) 550{ 551 WAVMuxContext *wav = s->priv_data; 552 AVIOContext *pb = s->pb; 553 int64_t start; 554 int ret; 555 556 avio_write(pb, ff_w64_guid_riff, sizeof(ff_w64_guid_riff)); 557 avio_wl64(pb, -1); 558 avio_write(pb, ff_w64_guid_wave, sizeof(ff_w64_guid_wave)); 559 start_guid(pb, ff_w64_guid_fmt, &start); 560 if ((ret = ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0)) < 0) { 561 av_log(s, AV_LOG_ERROR, "Codec %s not supported\n", 562 avcodec_get_name(s->streams[0]->codecpar->codec_id)); 563 return ret; 564 } 565 end_guid(pb, start); 566 567 if (s->streams[0]->codecpar->codec_tag != 0x01 /* hence for all other than PCM */ 568 && (s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { 569 start_guid(pb, ff_w64_guid_fact, &wav->fact_pos); 570 avio_wl64(pb, 0); 571 end_guid(pb, wav->fact_pos); 572 } 573 574 start_guid(pb, ff_w64_guid_data, &wav->data); 575 576 return 0; 577} 578 579static int w64_write_trailer(AVFormatContext *s) 580{ 581 AVIOContext *pb = s->pb; 582 WAVMuxContext *wav = s->priv_data; 583 int64_t file_size; 584 585 if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 586 end_guid(pb, wav->data); 587 588 file_size = avio_tell(pb); 589 avio_seek(pb, 16, SEEK_SET); 590 avio_wl64(pb, file_size); 591 592 if (s->streams[0]->codecpar->codec_tag != 0x01) { 593 int64_t number_of_samples; 594 595 number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration, 596 s->streams[0]->codecpar->sample_rate * (int64_t)s->streams[0]->time_base.num, 597 s->streams[0]->time_base.den); 598 avio_seek(pb, wav->fact_pos + 24, SEEK_SET); 599 avio_wl64(pb, number_of_samples); 600 } 601 602 avio_seek(pb, file_size, SEEK_SET); 603 } 604 605 return 0; 606} 607 608const AVOutputFormat ff_w64_muxer = { 609 .name = "w64", 610 .long_name = NULL_IF_CONFIG_SMALL("Sony Wave64"), 611 .extensions = "w64", 612 .priv_data_size = sizeof(WAVMuxContext), 613 .audio_codec = AV_CODEC_ID_PCM_S16LE, 614 .video_codec = AV_CODEC_ID_NONE, 615 .write_header = w64_write_header, 616 .write_packet = wav_write_packet, 617 .write_trailer = w64_write_trailer, 618 .flags = AVFMT_TS_NONSTRICT, 619 .codec_tag = ff_wav_codec_tags_list, 620}; 621#endif /* CONFIG_W64_MUXER */ 622