3 * Copyright (c) 2001, 2002 Fabrice Bellard
5 * This file is part of Libav.
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.
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.
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
25 #include "libavutil/dict.h"
26 #include "libavutil/common.h"
27 #include "libavutil/mathematics.h"
28 #include "libavutil/opt.h"
32 #include "avio_internal.h"
36 typedef struct WAVMuxContext {
45 static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen)
47 AVDictionaryEntry *tag;
50 if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
51 len = strlen(tag->value);
52 len = FFMIN(len, maxlen);
53 avio_write(s->pb, tag->value, len);
56 ffio_fill(s->pb, 0, maxlen - len);
59 static void bwf_write_bext_chunk(AVFormatContext *s)
61 AVDictionaryEntry *tmp_tag;
62 uint64_t time_reference = 0;
63 int64_t bext = ff_start_tag(s->pb, "bext");
65 bwf_write_bext_string(s, "description", 256);
66 bwf_write_bext_string(s, "originator", 32);
67 bwf_write_bext_string(s, "originator_reference", 32);
68 bwf_write_bext_string(s, "origination_date", 10);
69 bwf_write_bext_string(s, "origination_time", 8);
71 if (tmp_tag = av_dict_get(s->metadata, "time_reference", NULL, 0))
72 time_reference = strtoll(tmp_tag->value, NULL, 10);
73 avio_wl64(s->pb, time_reference);
74 avio_wl16(s->pb, 1); // set version to 1
76 if (tmp_tag = av_dict_get(s->metadata, "umid", NULL, 0)) {
77 unsigned char umidpart_str[17] = {0};
80 int len = strlen(tmp_tag->value+2);
82 for (i = 0; i < len/16; i++) {
83 memcpy(umidpart_str, tmp_tag->value + 2 + (i*16), 16);
84 umidpart = strtoll(umidpart_str, NULL, 16);
85 avio_wb64(s->pb, umidpart);
87 ffio_fill(s->pb, 0, 64 - i*8);
89 ffio_fill(s->pb, 0, 64); // zero UMID
91 ffio_fill(s->pb, 0, 190); // Reserved
93 if (tmp_tag = av_dict_get(s->metadata, "coding_history", NULL, 0))
94 avio_put_str(s->pb, tmp_tag->value);
96 ff_end_tag(s->pb, bext);
99 static int wav_write_header(AVFormatContext *s)
101 WAVMuxContext *wav = s->priv_data;
102 AVIOContext *pb = s->pb;
105 ffio_wfourcc(pb, "RIFF");
106 avio_wl32(pb, 0); /* file length */
107 ffio_wfourcc(pb, "WAVE");
110 fmt = ff_start_tag(pb, "fmt ");
111 if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) {
112 av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
113 s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE");
118 if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */
119 && s->pb->seekable) {
120 fact = ff_start_tag(pb, "fact");
122 ff_end_tag(pb, fact);
126 bwf_write_bext_chunk(s);
128 avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
129 wav->maxpts = wav->last_duration = 0;
130 wav->minpts = INT64_MAX;
133 ff_riff_write_info(s);
136 wav->data = ff_start_tag(pb, "data");
143 static int wav_write_packet(AVFormatContext *s, AVPacket *pkt)
145 AVIOContext *pb = s->pb;
146 WAVMuxContext *wav = s->priv_data;
147 avio_write(pb, pkt->data, pkt->size);
148 if(pkt->pts != AV_NOPTS_VALUE) {
149 wav->minpts = FFMIN(wav->minpts, pkt->pts);
150 wav->maxpts = FFMAX(wav->maxpts, pkt->pts);
151 wav->last_duration = pkt->duration;
153 av_log(s, AV_LOG_ERROR, "wav_write_packet: NOPTS\n");
157 static int wav_write_trailer(AVFormatContext *s)
159 AVIOContext *pb = s->pb;
160 WAVMuxContext *wav = s->priv_data;
165 if (s->pb->seekable) {
166 ff_end_tag(pb, wav->data);
168 /* update file size */
169 file_size = avio_tell(pb);
170 avio_seek(pb, 4, SEEK_SET);
171 avio_wl32(pb, (uint32_t)(file_size - 8));
172 avio_seek(pb, file_size, SEEK_SET);
176 if(s->streams[0]->codec->codec_tag != 0x01) {
177 /* Update num_samps in fact chunk */
178 int number_of_samples;
179 number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
180 s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
181 s->streams[0]->time_base.den);
182 avio_seek(pb, wav->data-12, SEEK_SET);
183 avio_wl32(pb, number_of_samples);
184 avio_seek(pb, file_size, SEEK_SET);
191 #define OFFSET(x) offsetof(WAVMuxContext, x)
192 #define ENC AV_OPT_FLAG_ENCODING_PARAM
193 static const AVOption options[] = {
194 { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
198 static const AVClass wav_muxer_class = {
199 .class_name = "WAV muxer",
200 .item_name = av_default_item_name,
202 .version = LIBAVUTIL_VERSION_INT,
205 AVOutputFormat ff_wav_muxer = {
207 .long_name = NULL_IF_CONFIG_SMALL("WAV / WAVE (Waveform Audio)"),
208 .mime_type = "audio/x-wav",
210 .priv_data_size = sizeof(WAVMuxContext),
211 .audio_codec = AV_CODEC_ID_PCM_S16LE,
212 .video_codec = AV_CODEC_ID_NONE,
213 .write_header = wav_write_header,
214 .write_packet = wav_write_packet,
215 .write_trailer = wav_write_trailer,
216 .flags = AVFMT_TS_NONSTRICT,
217 .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
218 .priv_class = &wav_muxer_class,