1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * raw FLAC muxer 3cabdff1aSopenharmony_ci * Copyright (c) 2006-2009 Justin Ruggles 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/avstring.h" 23cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 24cabdff1aSopenharmony_ci#include "libavutil/opt.h" 25cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h" 26cabdff1aSopenharmony_ci#include "libavcodec/flac.h" 27cabdff1aSopenharmony_ci#include "libavcodec/packet_internal.h" 28cabdff1aSopenharmony_ci#include "avformat.h" 29cabdff1aSopenharmony_ci#include "avio_internal.h" 30cabdff1aSopenharmony_ci#include "flacenc.h" 31cabdff1aSopenharmony_ci#include "id3v2.h" 32cabdff1aSopenharmony_ci#include "internal.h" 33cabdff1aSopenharmony_ci#include "version.h" 34cabdff1aSopenharmony_ci#include "vorbiscomment.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_citypedef struct FlacMuxerContext { 38cabdff1aSopenharmony_ci const AVClass *class; 39cabdff1aSopenharmony_ci int write_header; 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci int audio_stream_idx; 42cabdff1aSopenharmony_ci int waiting_pics; 43cabdff1aSopenharmony_ci /* audio packets are queued here until we get all the attached pictures */ 44cabdff1aSopenharmony_ci PacketList queue; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_ci /* updated streaminfo sent by the encoder at the end */ 47cabdff1aSopenharmony_ci uint8_t streaminfo[FLAC_STREAMINFO_SIZE]; 48cabdff1aSopenharmony_ci int updated_streaminfo; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci unsigned attached_types; 51cabdff1aSopenharmony_ci} FlacMuxerContext; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_cistatic int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_bytes, 54cabdff1aSopenharmony_ci int last_block) 55cabdff1aSopenharmony_ci{ 56cabdff1aSopenharmony_ci avio_w8(pb, last_block ? 0x81 : 0x01); 57cabdff1aSopenharmony_ci avio_wb24(pb, n_padding_bytes); 58cabdff1aSopenharmony_ci ffio_fill(pb, 0, n_padding_bytes); 59cabdff1aSopenharmony_ci return 0; 60cabdff1aSopenharmony_ci} 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_cistatic int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, 63cabdff1aSopenharmony_ci int last_block, int bitexact) 64cabdff1aSopenharmony_ci{ 65cabdff1aSopenharmony_ci const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; 66cabdff1aSopenharmony_ci int64_t len; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci len = ff_vorbiscomment_length(*m, vendor, NULL, 0); 71cabdff1aSopenharmony_ci if (len >= ((1<<24) - 4)) 72cabdff1aSopenharmony_ci return AVERROR(EINVAL); 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_ci avio_w8(pb, last_block ? 0x84 : 0x04); 75cabdff1aSopenharmony_ci avio_wb24(pb, len); 76cabdff1aSopenharmony_ci ff_vorbiscomment_write(pb, *m, vendor, NULL, 0); 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci return 0; 79cabdff1aSopenharmony_ci} 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_cistatic int flac_write_picture(struct AVFormatContext *s, AVPacket *pkt) 82cabdff1aSopenharmony_ci{ 83cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 84cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 85cabdff1aSopenharmony_ci const AVPixFmtDescriptor *pixdesc; 86cabdff1aSopenharmony_ci const CodecMime *mime = ff_id3v2_mime_tags; 87cabdff1aSopenharmony_ci AVDictionaryEntry *e; 88cabdff1aSopenharmony_ci const char *mimetype = NULL, *desc = ""; 89cabdff1aSopenharmony_ci const AVStream *st = s->streams[pkt->stream_index]; 90cabdff1aSopenharmony_ci int i, mimelen, desclen, type = 0, blocklen; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci if (!pkt->data) 93cabdff1aSopenharmony_ci return 0; 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci while (mime->id != AV_CODEC_ID_NONE) { 96cabdff1aSopenharmony_ci if (mime->id == st->codecpar->codec_id) { 97cabdff1aSopenharmony_ci mimetype = mime->str; 98cabdff1aSopenharmony_ci break; 99cabdff1aSopenharmony_ci } 100cabdff1aSopenharmony_ci mime++; 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci if (!mimetype) { 103cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot " 104cabdff1aSopenharmony_ci "write an attached picture.\n", st->index); 105cabdff1aSopenharmony_ci return AVERROR(EINVAL); 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci mimelen = strlen(mimetype); 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci /* get the picture type */ 110cabdff1aSopenharmony_ci e = av_dict_get(st->metadata, "comment", NULL, 0); 111cabdff1aSopenharmony_ci for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) { 112cabdff1aSopenharmony_ci if (!av_strcasecmp(e->value, ff_id3v2_picture_types[i])) { 113cabdff1aSopenharmony_ci type = i; 114cabdff1aSopenharmony_ci break; 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci if ((c->attached_types & (1 << type)) & 0x6) { 119cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Duplicate attachment for type '%s'\n", ff_id3v2_picture_types[type]); 120cabdff1aSopenharmony_ci return AVERROR(EINVAL); 121cabdff1aSopenharmony_ci } 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci if (type == 1 && (st->codecpar->codec_id != AV_CODEC_ID_PNG || 124cabdff1aSopenharmony_ci st->codecpar->width != 32 || 125cabdff1aSopenharmony_ci st->codecpar->height != 32)) { 126cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "File icon attachment must be a 32x32 PNG"); 127cabdff1aSopenharmony_ci return AVERROR(EINVAL); 128cabdff1aSopenharmony_ci } 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci c->attached_types |= (1 << type); 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci /* get the description */ 133cabdff1aSopenharmony_ci if ((e = av_dict_get(st->metadata, "title", NULL, 0))) 134cabdff1aSopenharmony_ci desc = e->value; 135cabdff1aSopenharmony_ci desclen = strlen(desc); 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_ci blocklen = 4 + 4 + mimelen + 4 + desclen + 4 + 4 + 4 + 4 + 4 + pkt->size; 138cabdff1aSopenharmony_ci if (blocklen >= 1<<24) { 139cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Picture block too big %d >= %d\n", blocklen, 1<<24); 140cabdff1aSopenharmony_ci return AVERROR(EINVAL); 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci avio_w8(pb, 0x06); 144cabdff1aSopenharmony_ci avio_wb24(pb, blocklen); 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci avio_wb32(pb, type); 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci avio_wb32(pb, mimelen); 149cabdff1aSopenharmony_ci avio_write(pb, mimetype, mimelen); 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci avio_wb32(pb, desclen); 152cabdff1aSopenharmony_ci avio_write(pb, desc, desclen); 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci avio_wb32(pb, st->codecpar->width); 155cabdff1aSopenharmony_ci avio_wb32(pb, st->codecpar->height); 156cabdff1aSopenharmony_ci if ((pixdesc = av_pix_fmt_desc_get(st->codecpar->format))) 157cabdff1aSopenharmony_ci avio_wb32(pb, av_get_bits_per_pixel(pixdesc)); 158cabdff1aSopenharmony_ci else 159cabdff1aSopenharmony_ci avio_wb32(pb, 0); 160cabdff1aSopenharmony_ci avio_wb32(pb, 0); 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci avio_wb32(pb, pkt->size); 163cabdff1aSopenharmony_ci avio_write(pb, pkt->data, pkt->size); 164cabdff1aSopenharmony_ci return 0; 165cabdff1aSopenharmony_ci} 166cabdff1aSopenharmony_ci 167cabdff1aSopenharmony_cistatic int flac_finish_header(struct AVFormatContext *s) 168cabdff1aSopenharmony_ci{ 169cabdff1aSopenharmony_ci int i, ret, padding = s->metadata_header_padding; 170cabdff1aSopenharmony_ci if (padding < 0) 171cabdff1aSopenharmony_ci padding = 8192; 172cabdff1aSopenharmony_ci /* The FLAC specification states that 24 bits are used to represent the 173cabdff1aSopenharmony_ci * size of a metadata block so we must clip this value to 2^24-1. */ 174cabdff1aSopenharmony_ci padding = av_clip_uintp2(padding, 24); 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 177cabdff1aSopenharmony_ci AVStream *st = s->streams[i]; 178cabdff1aSopenharmony_ci AVPacket *pkt = st->priv_data; 179cabdff1aSopenharmony_ci if (!pkt) 180cabdff1aSopenharmony_ci continue; 181cabdff1aSopenharmony_ci ret = flac_write_picture(s, pkt); 182cabdff1aSopenharmony_ci av_packet_unref(pkt); 183cabdff1aSopenharmony_ci if (ret < 0 && (s->error_recognition & AV_EF_EXPLODE)) 184cabdff1aSopenharmony_ci return ret; 185cabdff1aSopenharmony_ci } 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci ret = flac_write_block_comment(s->pb, &s->metadata, !padding, 188cabdff1aSopenharmony_ci s->flags & AVFMT_FLAG_BITEXACT); 189cabdff1aSopenharmony_ci if (ret) 190cabdff1aSopenharmony_ci return ret; 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci /* The command line flac encoder defaults to placing a seekpoint 193cabdff1aSopenharmony_ci * every 10s. So one might add padding to allow that later 194cabdff1aSopenharmony_ci * but there seems to be no simple way to get the duration here. 195cabdff1aSopenharmony_ci * So just add the amount requested by the user. */ 196cabdff1aSopenharmony_ci if (padding) 197cabdff1aSopenharmony_ci flac_write_block_padding(s->pb, padding, 1); 198cabdff1aSopenharmony_ci 199cabdff1aSopenharmony_ci return 0; 200cabdff1aSopenharmony_ci} 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_cistatic int flac_init(struct AVFormatContext *s) 203cabdff1aSopenharmony_ci{ 204cabdff1aSopenharmony_ci AVCodecParameters *par; 205cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 206cabdff1aSopenharmony_ci int i; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci c->audio_stream_idx = -1; 209cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 210cabdff1aSopenharmony_ci AVStream *st = s->streams[i]; 211cabdff1aSopenharmony_ci if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { 212cabdff1aSopenharmony_ci if (c->audio_stream_idx >= 0 || st->codecpar->codec_id != AV_CODEC_ID_FLAC) { 213cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Invalid audio stream. Exactly one FLAC " 214cabdff1aSopenharmony_ci "audio stream is required.\n"); 215cabdff1aSopenharmony_ci return AVERROR(EINVAL); 216cabdff1aSopenharmony_ci } 217cabdff1aSopenharmony_ci par = s->streams[i]->codecpar; 218cabdff1aSopenharmony_ci c->audio_stream_idx = i; 219cabdff1aSopenharmony_ci } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { 220cabdff1aSopenharmony_ci if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { 221cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Video stream #%d is not an attached picture. Ignoring\n", i); 222cabdff1aSopenharmony_ci continue; 223cabdff1aSopenharmony_ci } else if (st->codecpar->codec_id == AV_CODEC_ID_GIF) { 224cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "GIF image support is not implemented.\n"); 225cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 226cabdff1aSopenharmony_ci } else if (!c->write_header) { 227cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Can't write attached pictures without a header.\n"); 228cabdff1aSopenharmony_ci return AVERROR(EINVAL); 229cabdff1aSopenharmony_ci } 230cabdff1aSopenharmony_ci c->waiting_pics++; 231cabdff1aSopenharmony_ci } else { 232cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in FLAC.\n"); 233cabdff1aSopenharmony_ci return AVERROR(EINVAL); 234cabdff1aSopenharmony_ci } 235cabdff1aSopenharmony_ci } 236cabdff1aSopenharmony_ci if (c->audio_stream_idx < 0) { 237cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "No audio stream present.\n"); 238cabdff1aSopenharmony_ci return AVERROR(EINVAL); 239cabdff1aSopenharmony_ci } 240cabdff1aSopenharmony_ci 241cabdff1aSopenharmony_ci /* add the channel layout tag */ 242cabdff1aSopenharmony_ci if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE && 243cabdff1aSopenharmony_ci !(par->ch_layout.u.mask & ~0x3ffffULL) && 244cabdff1aSopenharmony_ci !ff_flac_is_native_layout(par->ch_layout.u.mask)) { 245cabdff1aSopenharmony_ci AVDictionaryEntry *chmask = av_dict_get(s->metadata, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", 246cabdff1aSopenharmony_ci NULL, 0); 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci if (chmask) { 249cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "A WAVEFORMATEXTENSIBLE_CHANNEL_MASK is " 250cabdff1aSopenharmony_ci "already present, this muxer will not overwrite it.\n"); 251cabdff1aSopenharmony_ci } else { 252cabdff1aSopenharmony_ci uint8_t buf[32]; 253cabdff1aSopenharmony_ci snprintf(buf, sizeof(buf), "0x%"PRIx64, par->ch_layout.u.mask); 254cabdff1aSopenharmony_ci av_dict_set(&s->metadata, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", buf, 0); 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci } 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci return 0; 259cabdff1aSopenharmony_ci} 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_cistatic int flac_write_header(struct AVFormatContext *s) 262cabdff1aSopenharmony_ci{ 263cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 264cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[c->audio_stream_idx]->codecpar; 265cabdff1aSopenharmony_ci int ret; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci if (!c->write_header) 268cabdff1aSopenharmony_ci return 0; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci ret = ff_flac_write_header(s->pb, par->extradata, 271cabdff1aSopenharmony_ci par->extradata_size, 0); 272cabdff1aSopenharmony_ci if (ret < 0) 273cabdff1aSopenharmony_ci return ret; 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci if (!c->waiting_pics) 276cabdff1aSopenharmony_ci ret = flac_finish_header(s); 277cabdff1aSopenharmony_ci 278cabdff1aSopenharmony_ci return ret; 279cabdff1aSopenharmony_ci} 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_cistatic int flac_write_audio_packet(struct AVFormatContext *s, AVPacket *pkt) 282cabdff1aSopenharmony_ci{ 283cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 284cabdff1aSopenharmony_ci uint8_t *streaminfo; 285cabdff1aSopenharmony_ci size_t streaminfo_size; 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_ci /* check for updated streaminfo */ 288cabdff1aSopenharmony_ci streaminfo = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, 289cabdff1aSopenharmony_ci &streaminfo_size); 290cabdff1aSopenharmony_ci if (streaminfo && streaminfo_size == FLAC_STREAMINFO_SIZE) { 291cabdff1aSopenharmony_ci memcpy(c->streaminfo, streaminfo, FLAC_STREAMINFO_SIZE); 292cabdff1aSopenharmony_ci c->updated_streaminfo = 1; 293cabdff1aSopenharmony_ci } 294cabdff1aSopenharmony_ci 295cabdff1aSopenharmony_ci if (pkt->size) 296cabdff1aSopenharmony_ci avio_write(s->pb, pkt->data, pkt->size); 297cabdff1aSopenharmony_ci return 0; 298cabdff1aSopenharmony_ci} 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_cistatic int flac_queue_flush(AVFormatContext *s) 301cabdff1aSopenharmony_ci{ 302cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 303cabdff1aSopenharmony_ci AVPacket *const pkt = ffformatcontext(s)->pkt; 304cabdff1aSopenharmony_ci int ret, write = 1; 305cabdff1aSopenharmony_ci 306cabdff1aSopenharmony_ci ret = flac_finish_header(s); 307cabdff1aSopenharmony_ci if (ret < 0) 308cabdff1aSopenharmony_ci write = 0; 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci while (c->queue.head) { 311cabdff1aSopenharmony_ci avpriv_packet_list_get(&c->queue, pkt); 312cabdff1aSopenharmony_ci if (write && (ret = flac_write_audio_packet(s, pkt)) < 0) 313cabdff1aSopenharmony_ci write = 0; 314cabdff1aSopenharmony_ci av_packet_unref(pkt); 315cabdff1aSopenharmony_ci } 316cabdff1aSopenharmony_ci return ret; 317cabdff1aSopenharmony_ci} 318cabdff1aSopenharmony_ci 319cabdff1aSopenharmony_cistatic int flac_write_trailer(struct AVFormatContext *s) 320cabdff1aSopenharmony_ci{ 321cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 322cabdff1aSopenharmony_ci int64_t file_size; 323cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 324cabdff1aSopenharmony_ci 325cabdff1aSopenharmony_ci if (c->waiting_pics) { 326cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "No packets were sent for some of the " 327cabdff1aSopenharmony_ci "attached pictures.\n"); 328cabdff1aSopenharmony_ci flac_queue_flush(s); 329cabdff1aSopenharmony_ci } 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci if (!c->write_header || !c->updated_streaminfo) 332cabdff1aSopenharmony_ci return 0; 333cabdff1aSopenharmony_ci 334cabdff1aSopenharmony_ci if (pb->seekable & AVIO_SEEKABLE_NORMAL) { 335cabdff1aSopenharmony_ci /* rewrite the STREAMINFO header block data */ 336cabdff1aSopenharmony_ci file_size = avio_tell(pb); 337cabdff1aSopenharmony_ci avio_seek(pb, 8, SEEK_SET); 338cabdff1aSopenharmony_ci avio_write(pb, c->streaminfo, FLAC_STREAMINFO_SIZE); 339cabdff1aSopenharmony_ci avio_seek(pb, file_size, SEEK_SET); 340cabdff1aSopenharmony_ci } else { 341cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "unable to rewrite FLAC header.\n"); 342cabdff1aSopenharmony_ci } 343cabdff1aSopenharmony_ci 344cabdff1aSopenharmony_ci return 0; 345cabdff1aSopenharmony_ci} 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_cistatic void flac_deinit(struct AVFormatContext *s) 348cabdff1aSopenharmony_ci{ 349cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci avpriv_packet_list_free(&c->queue); 352cabdff1aSopenharmony_ci for (unsigned i = 0; i < s->nb_streams; i++) 353cabdff1aSopenharmony_ci av_packet_free((AVPacket **)&s->streams[i]->priv_data); 354cabdff1aSopenharmony_ci} 355cabdff1aSopenharmony_ci 356cabdff1aSopenharmony_cistatic int flac_write_packet(struct AVFormatContext *s, AVPacket *pkt) 357cabdff1aSopenharmony_ci{ 358cabdff1aSopenharmony_ci FlacMuxerContext *c = s->priv_data; 359cabdff1aSopenharmony_ci int ret; 360cabdff1aSopenharmony_ci 361cabdff1aSopenharmony_ci if (pkt->stream_index == c->audio_stream_idx) { 362cabdff1aSopenharmony_ci if (c->waiting_pics) { 363cabdff1aSopenharmony_ci /* buffer audio packets until we get all the pictures */ 364cabdff1aSopenharmony_ci ret = avpriv_packet_list_put(&c->queue, pkt, NULL, 0); 365cabdff1aSopenharmony_ci if (ret < 0) { 366cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Out of memory in packet queue; skipping attached pictures\n"); 367cabdff1aSopenharmony_ci c->waiting_pics = 0; 368cabdff1aSopenharmony_ci ret = flac_queue_flush(s); 369cabdff1aSopenharmony_ci if (ret < 0) 370cabdff1aSopenharmony_ci return ret; 371cabdff1aSopenharmony_ci return flac_write_audio_packet(s, pkt); 372cabdff1aSopenharmony_ci } 373cabdff1aSopenharmony_ci } else 374cabdff1aSopenharmony_ci return flac_write_audio_packet(s, pkt); 375cabdff1aSopenharmony_ci } else { 376cabdff1aSopenharmony_ci AVStream *st = s->streams[pkt->stream_index]; 377cabdff1aSopenharmony_ci 378cabdff1aSopenharmony_ci if (!c->waiting_pics || 379cabdff1aSopenharmony_ci !(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) 380cabdff1aSopenharmony_ci return 0; 381cabdff1aSopenharmony_ci 382cabdff1aSopenharmony_ci /* warn only once for each stream */ 383cabdff1aSopenharmony_ci if (st->nb_frames == 1) { 384cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d," 385cabdff1aSopenharmony_ci " ignoring.\n", pkt->stream_index); 386cabdff1aSopenharmony_ci } 387cabdff1aSopenharmony_ci if (st->nb_frames >= 1) 388cabdff1aSopenharmony_ci return 0; 389cabdff1aSopenharmony_ci 390cabdff1aSopenharmony_ci st->priv_data = av_packet_clone(pkt); 391cabdff1aSopenharmony_ci if (!st->priv_data) 392cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Out of memory queueing an attached picture; skipping\n"); 393cabdff1aSopenharmony_ci c->waiting_pics--; 394cabdff1aSopenharmony_ci 395cabdff1aSopenharmony_ci /* flush the buffered audio packets */ 396cabdff1aSopenharmony_ci if (!c->waiting_pics && 397cabdff1aSopenharmony_ci (ret = flac_queue_flush(s)) < 0) 398cabdff1aSopenharmony_ci return ret; 399cabdff1aSopenharmony_ci } 400cabdff1aSopenharmony_ci 401cabdff1aSopenharmony_ci return 0; 402cabdff1aSopenharmony_ci} 403cabdff1aSopenharmony_ci 404cabdff1aSopenharmony_cistatic const AVOption flacenc_options[] = { 405cabdff1aSopenharmony_ci { "write_header", "Write the file header", offsetof(FlacMuxerContext, write_header), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, 406cabdff1aSopenharmony_ci { NULL }, 407cabdff1aSopenharmony_ci}; 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_cistatic const AVClass flac_muxer_class = { 410cabdff1aSopenharmony_ci .class_name = "flac muxer", 411cabdff1aSopenharmony_ci .item_name = av_default_item_name, 412cabdff1aSopenharmony_ci .option = flacenc_options, 413cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 414cabdff1aSopenharmony_ci}; 415cabdff1aSopenharmony_ci 416cabdff1aSopenharmony_ciconst AVOutputFormat ff_flac_muxer = { 417cabdff1aSopenharmony_ci .name = "flac", 418cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("raw FLAC"), 419cabdff1aSopenharmony_ci .priv_data_size = sizeof(FlacMuxerContext), 420cabdff1aSopenharmony_ci .mime_type = "audio/x-flac", 421cabdff1aSopenharmony_ci .extensions = "flac", 422cabdff1aSopenharmony_ci .audio_codec = AV_CODEC_ID_FLAC, 423cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_PNG, 424cabdff1aSopenharmony_ci .init = flac_init, 425cabdff1aSopenharmony_ci .write_header = flac_write_header, 426cabdff1aSopenharmony_ci .write_packet = flac_write_packet, 427cabdff1aSopenharmony_ci .write_trailer = flac_write_trailer, 428cabdff1aSopenharmony_ci .deinit = flac_deinit, 429cabdff1aSopenharmony_ci .flags = AVFMT_NOTIMESTAMPS, 430cabdff1aSopenharmony_ci .priv_class = &flac_muxer_class, 431cabdff1aSopenharmony_ci}; 432