static int lrc_write_header(AVFormatContext *s) { const AVDictionaryEntry *metadata_item; if(s->nb_streams != 1 || s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { av_log(s, AV_LOG_ERROR, "LRC supports only a single subtitle stream.\n"); return AVERROR(EINVAL); } if(s->streams[0]->codecpar->codec_id != AV_CODEC_ID_SUBRIP && s->streams[0]->codecpar->codec_id != AV_CODEC_ID_TEXT) { av_log(s, AV_LOG_ERROR, "Unsupported subtitle codec: %s\n", avcodec_get_name(s->streams[0]->codecpar->codec_id)); return AVERROR(EINVAL); } avpriv_set_pts_info(s->streams[0], 64, 1, 100); ff_standardize_creation_time(s); ff_metadata_conv_ctx(s, ff_lrc_metadata_conv, NULL); if(!(s->flags & AVFMT_FLAG_BITEXACT)) { // avoid breaking regression tests /* LRC provides a metadata slot for specifying encoder version * in addition to encoder name. We will store LIBAVFORMAT_VERSION * to it. */ av_dict_set(&s->metadata, "ve", AV_STRINGIFY(LIBAVFORMAT_VERSION), 0); } else { av_dict_set(&s->metadata, "ve", NULL, 0); } for(metadata_item = NULL; (metadata_item = av_dict_get(s->metadata, "", metadata_item, AV_DICT_IGNORE_SUFFIX));) { char *delim; if(!metadata_item->value[0]) { continue; } while((delim = strchr(metadata_item->value, '\n'))) { *delim = ' '; } while((delim = strchr(metadata_item->value, '\r'))) { *delim = ' '; } avio_printf(s->pb, "[%s:%s]\n", metadata_item->key, metadata_item->value); } avio_printf(s->pb, "\n"); return 0; }
int ff_ape_write_tag(AVFormatContext *s) { AVDictionaryEntry *e = NULL; int size, ret, count = 0; AVIOContext *dyn_bc = NULL; uint8_t *dyn_buf = NULL; if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0) goto end; // flags avio_wl32(dyn_bc, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER | APE_TAG_FLAG_IS_HEADER); ffio_fill(dyn_bc, 0, 8); // reserved ff_standardize_creation_time(s); while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) { int val_len; if (!string_is_ascii(e->key)) { av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n"); continue; } val_len = strlen(e->value); avio_wl32(dyn_bc, val_len); // value length avio_wl32(dyn_bc, 0); // item flags avio_put_str(dyn_bc, e->key); // key avio_write(dyn_bc, e->value, val_len); // value count++; } if (!count) goto end; size = avio_close_dyn_buf(dyn_bc, &dyn_buf); if (size <= 0) goto end; size += 20; // header avio_write(s->pb, "APETAGEX", 8); // id avio_wl32(s->pb, APE_TAG_VERSION); // version avio_wl32(s->pb, size); avio_wl32(s->pb, count); avio_write(s->pb, dyn_buf, size - 20); // footer avio_write(s->pb, "APETAGEX", 8); // id avio_wl32(s->pb, APE_TAG_VERSION); // version avio_wl32(s->pb, size); // size avio_wl32(s->pb, count); // tag count // flags avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER); ffio_fill(s->pb, 0, 8); // reserved end: if (dyn_bc && !dyn_buf) avio_close_dyn_buf(dyn_bc, &dyn_buf); av_freep(&dyn_buf); return ret; }
static void write_metadata(AVFormatContext *s, unsigned int ts) { AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; int write_duration_filesize = !(flv->flags & FLV_NO_DURATION_FILESIZE); int metadata_count = 0; int64_t metadata_count_pos; AVDictionaryEntry *tag = NULL; /* write meta_tag */ avio_w8(pb, FLV_TAG_TYPE_META); // tag type META flv->metadata_size_pos = avio_tell(pb); avio_wb24(pb, 0); // size of data part (sum of all parts below) avio_wb24(pb, ts); // timestamp avio_wb32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY); metadata_count_pos = avio_tell(pb); metadata_count = 4 * !!flv->video_par + 5 * !!flv->audio_par + 1 * !!flv->data_par; if (write_duration_filesize) { metadata_count += 2; // +2 for duration and file size } avio_wb32(pb, metadata_count); if (write_duration_filesize) { put_amf_string(pb, "duration"); flv->duration_offset = avio_tell(pb); // fill in the guessed duration, it'll be corrected later if incorrect put_amf_double(pb, s->duration / AV_TIME_BASE); } if (flv->video_par) { put_amf_string(pb, "width"); put_amf_double(pb, flv->video_par->width); put_amf_string(pb, "height"); put_amf_double(pb, flv->video_par->height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, flv->video_par->bit_rate / 1024.0); if (flv->framerate != 0.0) { put_amf_string(pb, "framerate"); put_amf_double(pb, flv->framerate); metadata_count++; } put_amf_string(pb, "videocodecid"); put_amf_double(pb, flv->video_par->codec_tag); } if (flv->audio_par) { put_amf_string(pb, "audiodatarate"); put_amf_double(pb, flv->audio_par->bit_rate / 1024.0); put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, flv->audio_par->sample_rate); put_amf_string(pb, "audiosamplesize"); put_amf_double(pb, flv->audio_par->codec_id == AV_CODEC_ID_PCM_U8 ? 8 : 16); put_amf_string(pb, "stereo"); put_amf_bool(pb, flv->audio_par->channels == 2); put_amf_string(pb, "audiocodecid"); put_amf_double(pb, flv->audio_par->codec_tag); } if (flv->data_par) { put_amf_string(pb, "datastream"); put_amf_double(pb, 0.0); } ff_standardize_creation_time(s); while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { if( !strcmp(tag->key, "width") ||!strcmp(tag->key, "height") ||!strcmp(tag->key, "videodatarate") ||!strcmp(tag->key, "framerate") ||!strcmp(tag->key, "videocodecid") ||!strcmp(tag->key, "audiodatarate") ||!strcmp(tag->key, "audiosamplerate") ||!strcmp(tag->key, "audiosamplesize") ||!strcmp(tag->key, "stereo") ||!strcmp(tag->key, "audiocodecid") ||!strcmp(tag->key, "duration") ||!strcmp(tag->key, "onMetaData") ||!strcmp(tag->key, "datasize") ||!strcmp(tag->key, "lasttimestamp") ||!strcmp(tag->key, "totalframes") ||!strcmp(tag->key, "hasAudio") ||!strcmp(tag->key, "hasVideo") ||!strcmp(tag->key, "hasCuePoints") ||!strcmp(tag->key, "hasMetadata") ||!strcmp(tag->key, "hasKeyframes") ){ av_log(s, AV_LOG_DEBUG, "Ignoring metadata for %s\n", tag->key); continue; } put_amf_string(pb, tag->key); avio_w8(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, tag->value); metadata_count++; } if (write_duration_filesize) { put_amf_string(pb, "filesize"); flv->filesize_offset = avio_tell(pb); put_amf_double(pb, 0); // delayed write } if (flv->flags & FLV_ADD_KEYFRAME_INDEX) { flv->acurframeindex = 0; flv->keyframe_index_size = 0; put_amf_string(pb, "hasVideo"); put_amf_bool(pb, !!flv->video_par); metadata_count++; put_amf_string(pb, "hasKeyframes"); put_amf_bool(pb, 1); metadata_count++; put_amf_string(pb, "hasAudio"); put_amf_bool(pb, !!flv->audio_par); metadata_count++; put_amf_string(pb, "hasMetadata"); put_amf_bool(pb, 1); metadata_count++; put_amf_string(pb, "canSeekToEnd"); put_amf_bool(pb, 1); metadata_count++; put_amf_string(pb, "datasize"); flv->datasize_offset = avio_tell(pb); flv->datasize = 0; put_amf_double(pb, flv->datasize); metadata_count++; put_amf_string(pb, "videosize"); flv->videosize_offset = avio_tell(pb); flv->videosize = 0; put_amf_double(pb, flv->videosize); metadata_count++; put_amf_string(pb, "audiosize"); flv->audiosize_offset = avio_tell(pb); flv->audiosize = 0; put_amf_double(pb, flv->audiosize); metadata_count++; put_amf_string(pb, "lasttimestamp"); flv->lasttimestamp_offset = avio_tell(pb); flv->lasttimestamp = 0; put_amf_double(pb, 0); metadata_count++; put_amf_string(pb, "lastkeyframetimestamp"); flv->lastkeyframetimestamp_offset = avio_tell(pb); flv->lastkeyframetimestamp = 0; put_amf_double(pb, 0); metadata_count++; put_amf_string(pb, "lastkeyframelocation"); flv->lastkeyframelocation_offset = avio_tell(pb); flv->lastkeyframelocation = 0; put_amf_double(pb, 0); metadata_count++; put_amf_string(pb, "keyframes"); put_amf_byte(pb, AMF_DATA_TYPE_OBJECT); metadata_count++; flv->keyframes_info_offset = avio_tell(pb); } put_amf_string(pb, ""); avio_w8(pb, AMF_END_OF_OBJECT); /* write total size of tag */ flv->metadata_totalsize = avio_tell(pb) - flv->metadata_size_pos - 10; avio_seek(pb, metadata_count_pos, SEEK_SET); avio_wb32(pb, metadata_count); avio_seek(pb, flv->metadata_size_pos, SEEK_SET); avio_wb24(pb, flv->metadata_totalsize); avio_skip(pb, flv->metadata_totalsize + 10 - 3); flv->metadata_totalsize_pos = avio_tell(pb); avio_wb32(pb, flv->metadata_totalsize + 11); }