#include "libavutil/intreadwrite.h"
#include "libavutil/intfloat.h"
+#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
#include "avformat.h"
#include "internal.h"
#include "ffm.h"
return 0;
}
+static int ffm_append_recommended_configuration(AVStream *st, char **conf)
+{
+ int ret;
+ size_t newsize;
+ av_assert0(conf && st);
+ if (!*conf)
+ return 0;
+ if (!st->recommended_encoder_configuration) {
+ st->recommended_encoder_configuration = *conf;
+ *conf = 0;
+ return 0;
+ }
+ newsize = strlen(*conf) + strlen(st->recommended_encoder_configuration) + 2;
+ if ((ret = av_reallocp(&st->recommended_encoder_configuration, newsize)) < 0)
+ return ret;
+ av_strlcat(st->recommended_encoder_configuration, ",", newsize);
+ av_strlcat(st->recommended_encoder_configuration, *conf, newsize);
+ av_freep(conf);
+ return 0;
+}
+
static int ffm2_read_header(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
AVIOContext *pb = s->pb;
AVCodecContext *codec;
int ret;
+ int f_main = 0, f_cprv, f_stvi, f_stau;
+ AVCodec *enc;
+ char *buffer;
ffm->packet_size = avio_rb32(pb);
if (ffm->packet_size != FFM_PACKET_SIZE) {
switch(id) {
case MKBETAG('M', 'A', 'I', 'N'):
+ if (f_main++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
avio_rb32(pb); /* nb_streams */
avio_rb32(pb); /* total bitrate */
break;
case MKBETAG('C', 'O', 'M', 'M'):
+ f_cprv = f_stvi = f_stau = 0;
st = avformat_new_stream(s, NULL);
if (!st) {
ret = AVERROR(ENOMEM);
if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0)
return AVERROR(ENOMEM);
}
- avio_seek(pb, next, SEEK_SET);
- id = avio_rb32(pb);
- size = avio_rb32(pb);
- next = avio_tell(pb) + size;
- switch(id) {
- case MKBETAG('S', 'T', 'V', 'I'):
- codec->time_base.num = avio_rb32(pb);
- codec->time_base.den = avio_rb32(pb);
- codec->width = avio_rb16(pb);
- codec->height = avio_rb16(pb);
- codec->gop_size = avio_rb16(pb);
- codec->pix_fmt = avio_rb32(pb);
- codec->qmin = avio_r8(pb);
- codec->qmax = avio_r8(pb);
- codec->max_qdiff = avio_r8(pb);
- codec->qcompress = avio_rb16(pb) / 10000.0;
- codec->qblur = avio_rb16(pb) / 10000.0;
- codec->bit_rate_tolerance = avio_rb32(pb);
- avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
- codec->rc_eq = av_strdup(rc_eq_buf);
- codec->rc_max_rate = avio_rb32(pb);
- codec->rc_min_rate = avio_rb32(pb);
- codec->rc_buffer_size = avio_rb32(pb);
- codec->i_quant_factor = av_int2double(avio_rb64(pb));
- codec->b_quant_factor = av_int2double(avio_rb64(pb));
- codec->i_quant_offset = av_int2double(avio_rb64(pb));
- codec->b_quant_offset = av_int2double(avio_rb64(pb));
- codec->dct_algo = avio_rb32(pb);
- codec->strict_std_compliance = avio_rb32(pb);
- codec->max_b_frames = avio_rb32(pb);
- codec->mpeg_quant = avio_rb32(pb);
- codec->intra_dc_precision = avio_rb32(pb);
- codec->me_method = avio_rb32(pb);
- codec->mb_decision = avio_rb32(pb);
- codec->nsse_weight = avio_rb32(pb);
- codec->frame_skip_cmp = avio_rb32(pb);
- codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
- codec->codec_tag = avio_rb32(pb);
- codec->thread_count = avio_r8(pb);
- codec->coder_type = avio_rb32(pb);
- codec->me_cmp = avio_rb32(pb);
- codec->me_subpel_quality = avio_rb32(pb);
- codec->me_range = avio_rb32(pb);
- codec->keyint_min = avio_rb32(pb);
- codec->scenechange_threshold = avio_rb32(pb);
- codec->b_frame_strategy = avio_rb32(pb);
- codec->qcompress = av_int2double(avio_rb64(pb));
- codec->qblur = av_int2double(avio_rb64(pb));
- codec->max_qdiff = avio_rb32(pb);
- codec->refs = avio_rb32(pb);
- break;
- case MKBETAG('S', 'T', 'A', 'U'):
- codec->sample_rate = avio_rb32(pb);
- codec->channels = avio_rl16(pb);
- codec->frame_size = avio_rl16(pb);
- break;
+ break;
+ case MKBETAG('S', 'T', 'V', 'I'):
+ if (f_stvi++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ codec->time_base.num = avio_rb32(pb);
+ codec->time_base.den = avio_rb32(pb);
+ codec->width = avio_rb16(pb);
+ codec->height = avio_rb16(pb);
+ codec->gop_size = avio_rb16(pb);
+ codec->pix_fmt = avio_rb32(pb);
+ codec->qmin = avio_r8(pb);
+ codec->qmax = avio_r8(pb);
+ codec->max_qdiff = avio_r8(pb);
+ codec->qcompress = avio_rb16(pb) / 10000.0;
+ codec->qblur = avio_rb16(pb) / 10000.0;
+ codec->bit_rate_tolerance = avio_rb32(pb);
+ avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
+ codec->rc_eq = av_strdup(rc_eq_buf);
+ codec->rc_max_rate = avio_rb32(pb);
+ codec->rc_min_rate = avio_rb32(pb);
+ codec->rc_buffer_size = avio_rb32(pb);
+ codec->i_quant_factor = av_int2double(avio_rb64(pb));
+ codec->b_quant_factor = av_int2double(avio_rb64(pb));
+ codec->i_quant_offset = av_int2double(avio_rb64(pb));
+ codec->b_quant_offset = av_int2double(avio_rb64(pb));
+ codec->dct_algo = avio_rb32(pb);
+ codec->strict_std_compliance = avio_rb32(pb);
+ codec->max_b_frames = avio_rb32(pb);
+ codec->mpeg_quant = avio_rb32(pb);
+ codec->intra_dc_precision = avio_rb32(pb);
+ codec->me_method = avio_rb32(pb);
+ codec->mb_decision = avio_rb32(pb);
+ codec->nsse_weight = avio_rb32(pb);
+ codec->frame_skip_cmp = avio_rb32(pb);
+ codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
+ codec->codec_tag = avio_rb32(pb);
+ codec->thread_count = avio_r8(pb);
+ codec->coder_type = avio_rb32(pb);
+ codec->me_cmp = avio_rb32(pb);
+ codec->me_subpel_quality = avio_rb32(pb);
+ codec->me_range = avio_rb32(pb);
+ codec->keyint_min = avio_rb32(pb);
+ codec->scenechange_threshold = avio_rb32(pb);
+ codec->b_frame_strategy = avio_rb32(pb);
+ codec->qcompress = av_int2double(avio_rb64(pb));
+ codec->qblur = av_int2double(avio_rb64(pb));
+ codec->max_qdiff = avio_rb32(pb);
+ codec->refs = avio_rb32(pb);
+ break;
+ case MKBETAG('S', 'T', 'A', 'U'):
+ if (f_stau++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ codec->sample_rate = avio_rb32(pb);
+ codec->channels = avio_rl16(pb);
+ codec->frame_size = avio_rl16(pb);
+ break;
+ case MKBETAG('C', 'P', 'R', 'V'):
+ if (f_cprv++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ enc = avcodec_find_encoder(codec->codec_id);
+ if (enc && enc->priv_data_size && enc->priv_class) {
+ buffer = av_malloc(size + 1);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, size, buffer, size + 1);
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ }
+ break;
+ case MKBETAG('S', '2', 'V', 'I'):
+ if (f_stvi++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ buffer = av_malloc(size);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, INT_MAX, buffer, size);
+ av_set_options_string(codec, buffer, "=", ",");
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ break;
+ case MKBETAG('S', '2', 'A', 'U'):
+ if (f_stau++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ buffer = av_malloc(size);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
}
+ avio_get_str(pb, INT_MAX, buffer, size);
+ av_set_options_string(codec, buffer, "=", ",");
+ ffm_append_recommended_configuration(st, &buffer);
break;
}
avio_seek(pb, next, SEEK_SET);