static int mp3_write_header(struct AVFormatContext *s) { MP3Context *mp3 = s->priv_data; int ret, i; if (mp3->id3v2_version && mp3->id3v2_version != 3 && mp3->id3v2_version != 4) { av_log(s, AV_LOG_ERROR, "Invalid ID3v2 version requested: %d. Only " "3, 4 or 0 (disabled) are allowed.\n", mp3->id3v2_version); return AVERROR(EINVAL); } /* check the streams -- we want exactly one audio and arbitrary number of * video (attached pictures) */ mp3->audio_stream_idx = -1; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { if (mp3->audio_stream_idx >= 0 || st->codec->codec_id != AV_CODEC_ID_MP3) { av_log(s, AV_LOG_ERROR, "Invalid audio stream. Exactly one MP3 " "audio stream is required.\n"); return AVERROR(EINVAL); } mp3->audio_stream_idx = i; } else if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) { av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in MP3.\n"); return AVERROR(EINVAL); } } if (mp3->audio_stream_idx < 0) { av_log(s, AV_LOG_ERROR, "No audio stream present.\n"); return AVERROR(EINVAL); } mp3->pics_to_write = s->nb_streams - 1; if (mp3->pics_to_write && !mp3->id3v2_version) { av_log(s, AV_LOG_ERROR, "Attached pictures were requested, but the " "ID3v2 header is disabled.\n"); return AVERROR(EINVAL); } if (mp3->id3v2_version) { ff_id3v2_start(&mp3->id3, s->pb, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC); ret = ff_id3v2_write_metadata(s, &mp3->id3); if (ret < 0) return ret; } if (!mp3->pics_to_write) { if (mp3->id3v2_version) ff_id3v2_finish(&mp3->id3, s->pb); mp3_write_xing(s); } return 0; }
static int mp3_queue_flush(AVFormatContext *s) { MP3Context *mp3 = s->priv_data; AVPacketList *pktl; int ret = 0, write = 1; ff_id3v2_finish(&mp3->id3, s->pb); mp3_write_xing(s); while ((pktl = mp3->queue)) { if (write && (ret = mp3_write_audio_packet(s, &pktl->pkt)) < 0) write = 0; av_free_packet(&pktl->pkt); mp3->queue = pktl->next; av_freep(&pktl); } mp3->queue_end = NULL; return ret; }
static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff) { int ret; uint64_t pos, end, size; ID3v2EncContext id3v2 = { 0 }; AVIOContext *pb = s->pb; AVPacketList *pict_list = aiff->pict_list; if (!pb->seekable) return 0; if (!s->metadata && !aiff->pict_list) return 0; avio_wl32(pb, MKTAG('I', 'D', '3', ' ')); avio_wb32(pb, 0); pos = avio_tell(pb); ff_id3v2_start(&id3v2, pb, aiff->id3v2_version, ID3v2_DEFAULT_MAGIC); ff_id3v2_write_metadata(s, &id3v2); while (pict_list) { if ((ret = ff_id3v2_write_apic(s, &id3v2, &pict_list->pkt)) < 0) return ret; pict_list = pict_list->next; } ff_id3v2_finish(&id3v2, pb, s->metadata_header_padding); end = avio_tell(pb); size = end - pos; /* Update chunk size */ avio_seek(pb, pos - 4, SEEK_SET); avio_wb32(pb, size); avio_seek(pb, end, SEEK_SET); if (size & 1) avio_w8(pb, 0); return 0; }