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