static int ffm_write_recommended_config(AVIOContext *pb, AVCodecContext *ctx, unsigned tag, const char *configuration) { int ret; const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id); AVIOContext *tmp; AVDictionaryEntry *t = NULL; AVDictionary *all = NULL, *comm = NULL, *prv = NULL; char *buf = NULL; if (!enc || !enc->priv_class || !enc->priv_data_size) { /* codec is not known/has no private options, so save everything as common options */ if (avio_open_dyn_buf(&tmp) < 0) return AVERROR(ENOMEM); avio_put_str(tmp, configuration); write_header_chunk(pb, tmp, tag); return 0; } if ((ret = av_dict_parse_string(&all, configuration, "=", ",", 0)) < 0) return ret; while ((t = av_dict_get(all, "", t, AV_DICT_IGNORE_SUFFIX))) { if (av_opt_find((void *)&enc->priv_class, t->key, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { if ((ret = av_dict_set(&prv, t->key, t->value, 0)) < 0) goto fail; } else if ((ret = av_dict_set(&comm, t->key, t->value, 0)) < 0) goto fail; } if (comm) { if ((ret = av_dict_get_string(comm, &buf, '=', ',')) < 0 || (ret = avio_open_dyn_buf(&tmp)) < 0) goto fail; avio_put_str(tmp, buf); av_freep(&buf); write_header_chunk(pb, tmp, tag); } if (prv) { if ((ret = av_dict_get_string(prv, &buf, '=', ',')) < 0 || (ret = avio_open_dyn_buf(&tmp)) < 0) goto fail; avio_put_str(tmp, buf); write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V')); } fail: av_free(buf); av_dict_free(&all); av_dict_free(&comm); av_dict_free(&prv); return ret; }
static int ffm_write_header_codec_private_ctx(AVFormatContext *s, AVCodecContext *ctx, int type) { AVIOContext *pb = s->pb; AVIOContext *tmp; char *buf = NULL; int ret; const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id); if (!enc) { av_log(s, AV_LOG_WARNING, "Stream codec is not found. Codec private options are not stored.\n"); return 0; } if (ctx->priv_data && enc->priv_class && enc->priv_data_size) { if ((ret = av_opt_serialize(ctx->priv_data, AV_OPT_FLAG_ENCODING_PARAM | type, AV_OPT_SERIALIZE_SKIP_DEFAULTS, &buf, '=', ',')) < 0) return ret; if (buf && strlen(buf)) { if (avio_open_dyn_buf(&tmp) < 0) { av_free(buf); return AVERROR(ENOMEM); } avio_put_str(tmp, buf); write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V')); } av_free(buf); } return 0; }
static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecContext *ctx, unsigned tag, int type) { AVIOContext *tmp; char *buf = NULL; int ret, need_coma = 0; #define SKIP_DEFAULTS AV_OPT_SERIALIZE_SKIP_DEFAULTS #define OPT_FLAGS_EXACT AV_OPT_SERIALIZE_OPT_FLAGS_EXACT #define ENC AV_OPT_FLAG_ENCODING_PARAM if (avio_open_dyn_buf(&tmp) < 0) return AVERROR(ENOMEM); if ((ret = av_opt_serialize(ctx, ENC | type, SKIP_DEFAULTS, &buf, '=', ',')) < 0) goto fail; if (buf && strlen(buf)) { avio_write(tmp, buf, strlen(buf)); av_freep(&buf); need_coma = 1; } if ((ret = av_opt_serialize(ctx, 0, SKIP_DEFAULTS | OPT_FLAGS_EXACT, &buf, '=', ',')) < 0) goto fail; if (buf && strlen(buf)) { if (need_coma) avio_w8(tmp, ','); avio_write(tmp, buf, strlen(buf)); } av_freep(&buf); avio_w8(tmp, 0); write_header_chunk(pb, tmp, tag); return 0; fail: av_free(buf); ffio_free_dyn_buf(&tmp); return ret; #undef SKIP_DEFAULTS #undef OPT_FLAGS_EXACT #undef ENC }
static int ffm_write_header(AVFormatContext *s) { FFMContext *ffm = s->priv_data; AVDictionaryEntry *t; AVStream *st; AVIOContext *pb = s->pb; AVCodecContext *codec; int bit_rate, i; if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { int ret = av_parse_time(&ffm->start_time, t->value, 0); if (ret < 0) return ret; } ffm->packet_size = FFM_PACKET_SIZE; /* header */ avio_wl32(pb, MKTAG('F', 'F', 'M', '2')); avio_wb32(pb, ffm->packet_size); avio_wb64(pb, 0); /* current write position */ if(avio_open_dyn_buf(&pb) < 0) return AVERROR(ENOMEM); avio_wb32(pb, s->nb_streams); bit_rate = 0; for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; bit_rate += st->codec->bit_rate; } avio_wb32(pb, bit_rate); write_header_chunk(s->pb, pb, MKBETAG('M', 'A', 'I', 'N')); /* list of streams */ for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; avpriv_set_pts_info(st, 64, 1, 1000000); if(avio_open_dyn_buf(&pb) < 0) return AVERROR(ENOMEM); codec = st->codec; /* generic info */ avio_wb32(pb, codec->codec_id); avio_w8(pb, codec->codec_type); avio_wb32(pb, codec->bit_rate); avio_wb32(pb, codec->flags); avio_wb32(pb, codec->flags2); avio_wb32(pb, codec->debug); if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { avio_wb32(pb, codec->extradata_size); avio_write(pb, codec->extradata, codec->extradata_size); } write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M')); if(avio_open_dyn_buf(&pb) < 0) return AVERROR(ENOMEM); /* specific info */ switch(codec->codec_type) { case AVMEDIA_TYPE_VIDEO: avio_wb32(pb, codec->time_base.num); avio_wb32(pb, codec->time_base.den); avio_wb16(pb, codec->width); avio_wb16(pb, codec->height); avio_wb16(pb, codec->gop_size); avio_wb32(pb, codec->pix_fmt); avio_w8(pb, codec->qmin); avio_w8(pb, codec->qmax); avio_w8(pb, codec->max_qdiff); avio_wb16(pb, (int) (codec->qcompress * 10000.0)); avio_wb16(pb, (int) (codec->qblur * 10000.0)); avio_wb32(pb, codec->bit_rate_tolerance); avio_put_str(pb, codec->rc_eq ? codec->rc_eq : "tex^qComp"); avio_wb32(pb, codec->rc_max_rate); avio_wb32(pb, codec->rc_min_rate); avio_wb32(pb, codec->rc_buffer_size); avio_wb64(pb, av_double2int(codec->i_quant_factor)); avio_wb64(pb, av_double2int(codec->b_quant_factor)); avio_wb64(pb, av_double2int(codec->i_quant_offset)); avio_wb64(pb, av_double2int(codec->b_quant_offset)); avio_wb32(pb, codec->dct_algo); avio_wb32(pb, codec->strict_std_compliance); avio_wb32(pb, codec->max_b_frames); avio_wb32(pb, codec->mpeg_quant); avio_wb32(pb, codec->intra_dc_precision); avio_wb32(pb, codec->me_method); avio_wb32(pb, codec->mb_decision); avio_wb32(pb, codec->nsse_weight); avio_wb32(pb, codec->frame_skip_cmp); avio_wb64(pb, av_double2int(codec->rc_buffer_aggressivity)); avio_wb32(pb, codec->codec_tag); avio_w8(pb, codec->thread_count); avio_wb32(pb, codec->coder_type); avio_wb32(pb, codec->me_cmp); avio_wb32(pb, codec->me_subpel_quality); avio_wb32(pb, codec->me_range); avio_wb32(pb, codec->keyint_min); avio_wb32(pb, codec->scenechange_threshold); avio_wb32(pb, codec->b_frame_strategy); avio_wb64(pb, av_double2int(codec->qcompress)); avio_wb64(pb, av_double2int(codec->qblur)); avio_wb32(pb, codec->max_qdiff); avio_wb32(pb, codec->refs); write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'V', 'I')); break; case AVMEDIA_TYPE_AUDIO: avio_wb32(pb, codec->sample_rate); avio_wl16(pb, codec->channels); avio_wl16(pb, codec->frame_size); write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'A', 'U')); break; default: return -1; } } pb = s->pb; avio_wb64(pb, 0); // end of header /* flush until end of block reached */ while ((avio_tell(pb) % ffm->packet_size) != 0) avio_w8(pb, 0); avio_flush(pb); /* init packet mux */ ffm->packet_ptr = ffm->packet; ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE; av_assert0(ffm->packet_end >= ffm->packet); ffm->frame_offset = 0; ffm->dts = 0; ffm->first_packet = 1; return 0; }
static int ffm_write_header(AVFormatContext *s) { FFMContext *ffm = s->priv_data; AVDictionaryEntry *t; AVStream *st; AVIOContext *pb = s->pb; AVCodecContext *codec; int bit_rate, i, ret; if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { ret = av_parse_time(&ffm->start_time, t->value, 0); if (ret < 0) return ret; } ffm->packet_size = FFM_PACKET_SIZE; /* header */ avio_wl32(pb, MKTAG('F', 'F', 'M', '2')); avio_wb32(pb, ffm->packet_size); avio_wb64(pb, 0); /* current write position */ if(avio_open_dyn_buf(&pb) < 0) return AVERROR(ENOMEM); avio_wb32(pb, s->nb_streams); bit_rate = 0; for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; bit_rate += st->codec->bit_rate; } avio_wb32(pb, bit_rate); write_header_chunk(s->pb, pb, MKBETAG('M', 'A', 'I', 'N')); /* list of streams */ for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; avpriv_set_pts_info(st, 64, 1, 1000000); if(avio_open_dyn_buf(&pb) < 0) return AVERROR(ENOMEM); codec = st->codec; /* generic info */ avio_wb32(pb, codec->codec_id); avio_w8(pb, codec->codec_type); avio_wb32(pb, codec->bit_rate); avio_wb32(pb, codec->flags); avio_wb32(pb, codec->flags2); avio_wb32(pb, codec->debug); if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) { avio_wb32(pb, codec->extradata_size); avio_write(pb, codec->extradata, codec->extradata_size); } write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M')); /* specific info */ switch(codec->codec_type) { case AVMEDIA_TYPE_VIDEO: if (st->recommended_encoder_configuration) { av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", st->recommended_encoder_configuration); if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'V', 'I'), st->recommended_encoder_configuration)) < 0) return ret; } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'V', 'I'), AV_OPT_FLAG_VIDEO_PARAM)) < 0 || (ret = ffm_write_header_codec_private_ctx(s, codec, AV_OPT_FLAG_VIDEO_PARAM)) < 0) return ret; break; case AVMEDIA_TYPE_AUDIO: if (st->recommended_encoder_configuration) { av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", st->recommended_encoder_configuration); if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'A', 'U'), st->recommended_encoder_configuration)) < 0) return ret; } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'A', 'U'), AV_OPT_FLAG_AUDIO_PARAM)) < 0 || (ret = ffm_write_header_codec_private_ctx(s, codec, AV_OPT_FLAG_AUDIO_PARAM)) < 0) return ret; break; default: return -1; } } pb = s->pb; avio_wb64(pb, 0); // end of header /* flush until end of block reached */ while ((avio_tell(pb) % ffm->packet_size) != 0) avio_w8(pb, 0); avio_flush(pb); /* init packet mux */ ffm->packet_ptr = ffm->packet; ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE; av_assert0(ffm->packet_end >= ffm->packet); ffm->frame_offset = 0; ffm->dts = 0; ffm->first_packet = 1; return 0; }