return -1;
}
- // only look for metadata values when we are not nested and key != NULL
- if (depth == 1 && key) {
- acodec = astream ? astream->codec : NULL;
- vcodec = vstream ? vstream->codec : NULL;
-
- if (amf_type == AMF_DATA_TYPE_NUMBER ||
- amf_type == AMF_DATA_TYPE_BOOL) {
- if (!strcmp(key, "duration"))
- s->duration = num_val * AV_TIME_BASE;
- else if (!strcmp(key, "videodatarate") && vcodec &&
- 0 <= (int)(num_val * 1024.0))
- vcodec->bit_rate = num_val * 1024.0;
- else if (!strcmp(key, "audiodatarate") && acodec &&
- 0 <= (int)(num_val * 1024.0))
- acodec->bit_rate = num_val * 1024.0;
- else if (!strcmp(key, "datastream")) {
- AVStream *st = create_stream(s, AVMEDIA_TYPE_DATA);
- if (!st)
- return AVERROR(ENOMEM);
- st->codec->codec_id = AV_CODEC_ID_TEXT;
- } else if (flv->trust_metadata) {
- if (!strcmp(key, "videocodecid") && vcodec) {
- flv_set_video_codec(s, vstream, num_val, 0);
- } else if (!strcmp(key, "audiocodecid") && acodec) {
- int id = ((int)num_val) << FLV_AUDIO_CODECID_OFFSET;
- flv_set_audio_codec(s, astream, acodec, id);
- } else if (!strcmp(key, "audiosamplerate") && acodec) {
- acodec->sample_rate = num_val;
- } else if (!strcmp(key, "audiosamplesize") && acodec) {
- acodec->bits_per_coded_sample = num_val;
- } else if (!strcmp(key, "stereo") && acodec) {
- acodec->channels = num_val + 1;
- acodec->channel_layout = acodec->channels == 2 ?
- AV_CH_LAYOUT_STEREO :
- AV_CH_LAYOUT_MONO;
- } else if (!strcmp(key, "width") && vcodec) {
- vcodec->width = num_val;
- } else if (!strcmp(key, "height") && vcodec) {
- vcodec->height = num_val;
+ if (key) {
+ // stream info doesn't live any deeper than the first object
+ if (depth == 1) {
+ acodec = astream ? astream->codec : NULL;
+ vcodec = vstream ? vstream->codec : NULL;
+
+ if (amf_type == AMF_DATA_TYPE_NUMBER ||
+ amf_type == AMF_DATA_TYPE_BOOL) {
+ if (!strcmp(key, "duration"))
+ s->duration = num_val * AV_TIME_BASE;
+ else if (!strcmp(key, "videodatarate") && vcodec &&
+ 0 <= (int)(num_val * 1024.0))
+ vcodec->bit_rate = num_val * 1024.0;
+ else if (!strcmp(key, "audiodatarate") && acodec &&
+ 0 <= (int)(num_val * 1024.0))
+ acodec->bit_rate = num_val * 1024.0;
+ else if (!strcmp(key, "datastream")) {
+ AVStream *st = create_stream(s, AVMEDIA_TYPE_DATA);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_id = AV_CODEC_ID_TEXT;
+ } else if (flv->trust_metadata) {
+ if (!strcmp(key, "videocodecid") && vcodec) {
+ flv_set_video_codec(s, vstream, num_val, 0);
+ } else if (!strcmp(key, "audiocodecid") && acodec) {
+ int id = ((int)num_val) << FLV_AUDIO_CODECID_OFFSET;
+ flv_set_audio_codec(s, astream, acodec, id);
+ } else if (!strcmp(key, "audiosamplerate") && acodec) {
+ acodec->sample_rate = num_val;
+ } else if (!strcmp(key, "audiosamplesize") && acodec) {
+ acodec->bits_per_coded_sample = num_val;
+ } else if (!strcmp(key, "stereo") && acodec) {
+ acodec->channels = num_val + 1;
+ acodec->channel_layout = acodec->channels == 2 ?
+ AV_CH_LAYOUT_STEREO :
+ AV_CH_LAYOUT_MONO;
+ } else if (!strcmp(key, "width") && vcodec) {
+ vcodec->width = num_val;
+ } else if (!strcmp(key, "height") && vcodec) {
+ vcodec->height = num_val;
+ }
}
}
}
!strcmp(key, "audiosamplerate") ||
!strcmp(key, "audiosamplesize") ||
!strcmp(key, "stereo") ||
- !strcmp(key, "audiocodecid"))
+ !strcmp(key, "audiocodecid") ||
+ !strcmp(key, "datastream"))
return 0;
+ s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
if (amf_type == AMF_DATA_TYPE_BOOL) {
av_strlcpy(str_val, num_val > 0 ? "true" : "false",
sizeof(str_val));
if (!strcmp(buffer, "onTextData"))
return 1;
- if (strcmp(buffer, "onMetaData"))
+ if (strcmp(buffer, "onMetaData") && strcmp(buffer, "onCuePoint"))
return -1;
// find the streams now so that amf_parse_object doesn't need to do
avio_skip(s->pb, 4);
flags = avio_r8(s->pb);
- /* old flvtool cleared this field */
- /* FIXME: better fix needed */
- if (!flags) {
- flags = FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO;
- av_log(s, AV_LOG_WARNING,
- "Broken FLV file, which says no streams present, "
- "this might fail\n");
- }
s->ctx_flags |= AVFMTCTX_NOHEADER;
}
}
+static int amf_skip_tag(AVIOContext *pb, AMFDataType type)
+{
+ int nb = -1, ret, parse_name = 1;
+
+ switch (type) {
+ case AMF_DATA_TYPE_NUMBER:
+ avio_skip(pb, 8);
+ break;
+ case AMF_DATA_TYPE_BOOL:
+ avio_skip(pb, 1);
+ break;
+ case AMF_DATA_TYPE_STRING:
+ avio_skip(pb, avio_rb16(pb));
+ break;
+ case AMF_DATA_TYPE_ARRAY:
+ parse_name = 0;
+ case AMF_DATA_TYPE_MIXEDARRAY:
+ nb = avio_rb32(pb);
+ case AMF_DATA_TYPE_OBJECT:
+ while(!pb->eof_reached && (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY)) {
+ if (parse_name) {
+ int size = avio_rb16(pb);
+ if (!size) {
+ avio_skip(pb, 1);
+ break;
+ }
+ avio_skip(pb, size);
+ }
+ if ((ret = amf_skip_tag(pb, avio_r8(pb))) < 0)
+ return ret;
+ }
+ break;
+ case AMF_DATA_TYPE_NULL:
+ case AMF_DATA_TYPE_OBJECT_END:
+ break;
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+ return 0;
+}
+
static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
int64_t dts, int64_t next)
{
AVIOContext *pb = s->pb;
AVStream *st = NULL;
- AMFDataType type;
char buf[20];
- int ret, i, length;
+ int ret = AVERROR_INVALIDDATA;
+ int i, length = -1;
- type = avio_r8(pb);
- if (type == AMF_DATA_TYPE_MIXEDARRAY)
+ switch (avio_r8(pb)) {
+ case AMF_DATA_TYPE_MIXEDARRAY:
avio_seek(pb, 4, SEEK_CUR);
- else if (type != AMF_DATA_TYPE_OBJECT)
- return AVERROR_INVALIDDATA;
-
- amf_get_string(pb, buf, sizeof(buf));
- if (strcmp(buf, "type") || avio_r8(pb) != AMF_DATA_TYPE_STRING)
- return AVERROR_INVALIDDATA;
+ case AMF_DATA_TYPE_OBJECT:
+ break;
+ default:
+ goto skip;
+ }
- amf_get_string(pb, buf, sizeof(buf));
- // FIXME parse it as codec_id
- amf_get_string(pb, buf, sizeof(buf));
- if (strcmp(buf, "text") || avio_r8(pb) != AMF_DATA_TYPE_STRING)
- return AVERROR_INVALIDDATA;
+ while ((ret = amf_get_string(pb, buf, sizeof(buf))) > 0) {
+ AMFDataType type = avio_r8(pb);
+ if (type == AMF_DATA_TYPE_STRING && !strcmp(buf, "text")) {
+ length = avio_rb16(pb);
+ ret = av_get_packet(pb, pkt, length);
+ if (ret < 0)
+ goto skip;
+ else
+ break;
+ } else {
+ if ((ret = amf_skip_tag(pb, type)) < 0)
+ goto skip;
+ }
+ }
- length = avio_rb16(pb);
- ret = av_get_packet(s->pb, pkt, length);
- if (ret < 0)
- return AVERROR(EIO);
+ if (length < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto skip;
+ }
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
if (i == s->nb_streams) {
st = create_stream(s, AVMEDIA_TYPE_DATA);
if (!st)
- return AVERROR_INVALIDDATA;
+ return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_TEXT;
}
pkt->stream_index = st->index;
pkt->flags |= AV_PKT_FLAG_KEY;
+skip:
avio_seek(s->pb, next + 4, SEEK_SET);
return ret;
return flv_data_packet(s, pkt, dts, next);
} else /* skip packet */
av_log(s, AV_LOG_DEBUG,
- "skipping flv packet: type %d, size %d, flags %d\n",
+ "Skipping flv packet: type %d, size %d, flags %d.\n",
type, size, flags);
skip:
break;
}
}
- if (i == s->nb_streams)
+ if (i == s->nb_streams) {
st = create_stream(s, is_audio ? AVMEDIA_TYPE_AUDIO
: AVMEDIA_TYPE_VIDEO);
+ if (!st)
+ return AVERROR(ENOMEM);
+ }
av_dlog(s, "%d %X %d \n", is_audio, flags, st->discard);
+
+ if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY ||
+ is_audio)
+ av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
+
if ((st->discard >= AVDISCARD_NONKEY &&
!((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || is_audio)) ||
(st->discard >= AVDISCARD_BIDIR &&
avio_seek(s->pb, next, SEEK_SET);
continue;
}
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)
- av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
break;
}
} else {
AVCodecContext ctx;
ctx.sample_rate = sample_rate;
+ ctx.bits_per_coded_sample = bits_per_coded_sample;
flv_set_audio_codec(s, st, &ctx, flags & FLV_AUDIO_CODECID_MASK);
sample_rate = ctx.sample_rate;
}
// sign extension
int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
pts = dts + cts;
- if (cts < 0) { // dts are wrong
+ if (cts < 0 && !flv->wrong_dts) { // dts might be wrong
flv->wrong_dts = 1;
av_log(s, AV_LOG_WARNING,
- "negative cts, previous timestamps might be wrong\n");
+ "Negative cts, previous timestamps might be wrong.\n");
}
- if (flv->wrong_dts)
- dts = AV_NOPTS_VALUE;
}
if (type == 0) {
if (st->codec->extradata) {
return ret;
if (st->codec->codec_id == AV_CODEC_ID_AAC) {
MPEG4AudioConfig cfg;
+
+ /* Workaround for buggy Omnia A/XE encoder */
+ AVDictionaryEntry *t = av_dict_get(s->metadata, "Encoder", NULL, 0);
+ if (t && !strcmp(t->value, "Omnia A/XE"))
+ st->codec->extradata_size = 2;
+
avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
st->codec->extradata_size * 8, 1);
st->codec->channels = cfg.channels;