X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fflvdec.c;h=fca6f82f5c56b497ff7f2e7ec1c4584d8d65e327;hb=2086d635c36c2865d1a0145c56e448b30af59ba0;hp=972e3333133f530ce85f47b33ce2c63b02ca791c;hpb=34a0a9746b2f441db7c45983838a88aa87a33834;p=ffmpeg diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 972e3333133..fca6f82f5c5 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -30,8 +30,8 @@ #include "libavutil/opt.h" #include "libavutil/intfloat.h" #include "libavutil/mathematics.h" +#include "libavutil/time_internal.h" #include "libavcodec/bytestream.h" -#include "libavcodec/mpeg4audio.h" #include "avformat.h" #include "internal.h" #include "avio_internal.h" @@ -41,6 +41,8 @@ #define RESYNC_BUFFER_SIZE (1<<20) +#define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion + typedef struct FLVContext { const AVClass *class; ///< Class for private options. int trust_metadata; ///< configure streams according onMetaData @@ -77,7 +79,13 @@ typedef struct FLVContext { int64_t time_pos; } FLVContext; -static int probe(AVProbeData *p, int live) +/* AMF date type */ +typedef struct amf_date { + double milliseconds; + int16_t timezone; +} amf_date; + +static int probe(const AVProbeData *p, int live) { const uint8_t *d = p->buf; unsigned offset = AV_RB32(d + 5); @@ -96,16 +104,30 @@ static int probe(AVProbeData *p, int live) return 0; } -static int flv_probe(AVProbeData *p) +static int flv_probe(const AVProbeData *p) { return probe(p, 0); } -static int live_flv_probe(AVProbeData *p) +static int live_flv_probe(const AVProbeData *p) { return probe(p, 1); } +static int kux_probe(const AVProbeData *p) +{ + const uint8_t *d = p->buf; + + if (d[0] == 'K' && + d[1] == 'D' && + d[2] == 'K' && + d[3] == 0 && + d[4] == 0) { + return AVPROBE_SCORE_EXTENSION + 1; + } + return 0; +} + static void add_keyframes_index(AVFormatContext *s) { FLVContext *flv = s->priv_data; @@ -120,7 +142,7 @@ static void add_keyframes_index(AVFormatContext *s) av_assert0(flv->last_keyframe_stream_index <= s->nb_streams); stream = s->streams[flv->last_keyframe_stream_index]; - if (stream->nb_index_entries == 0) { + if (stream->internal->nb_index_entries == 0) { for (i = 0; i < flv->keyframe_count; i++) { av_log(s, AV_LOG_TRACE, "keyframe filepositions = %"PRId64" times = %"PRId64"\n", flv->keyframe_filepositions[i], flv->keyframe_times[i] * 1000); @@ -362,13 +384,18 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) { + int ret; int length = avio_rb16(ioc); if (length >= buffsize) { avio_skip(ioc, length); return -1; } - avio_read(ioc, buffer, length); + ret = avio_read(ioc, buffer, length); + if (ret < 0) + return ret; + if (ret < length) + return AVERROR_INVALIDDATA; buffer[length] = '\0'; @@ -386,7 +413,7 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t m int64_t initial_pos = avio_tell(ioc); if (flv->keyframe_count > 0) { - av_log(s, AV_LOG_DEBUG, "keyframes have been paresed\n"); + av_log(s, AV_LOG_DEBUG, "keyframes have been parsed\n"); return 0; } av_assert0(!flv->keyframe_times); @@ -426,9 +453,13 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t m } for (i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) { + double d; if (avio_r8(ioc) != AMF_DATA_TYPE_NUMBER) goto invalid; - current_array[0][i] = av_int2double(avio_rb64(ioc)); + d = av_int2double(avio_rb64(ioc)); + if (isnan(d) || d < INT64_MIN || d > INT64_MAX) + goto invalid; + current_array[0][i] = d; } if (times && filepositions) { // All done, exiting at a position allowing amf_parse_object @@ -471,9 +502,15 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AMFDataType amf_type; char str_val[1024]; double num_val; + amf_date date; + + if (depth > MAX_DEPTH) + return AVERROR_PATCHWELCOME; num_val = 0; ioc = s->pb; + if (avio_feof(ioc)) + return AVERROR_EOF; amf_type = avio_r8(ioc); switch (amf_type) { @@ -493,8 +530,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, if (key && (ioc->seekable & AVIO_SEEKABLE_NORMAL) && !strcmp(KEYFRAMES_TAG, key) && depth == 1) - if (parse_keyframes_index(s, ioc, - max_pos) < 0) + if (parse_keyframes_index(s, ioc, max_pos) < 0) av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n"); else add_keyframes_index(s); @@ -542,7 +578,9 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, } break; case AMF_DATA_TYPE_DATE: - avio_skip(ioc, 8 + 2); // timestamp (double) and UTC offset (int16) + // timestamp (double) and UTC offset (int16) + date.milliseconds = av_int2double(avio_rb64(ioc)); + date.timezone = avio_rb16(ioc); break; default: // unsupported type, we couldn't skip av_log(s, AV_LOG_ERROR, "unsupported amf type %d\n", amf_type); @@ -641,8 +679,18 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, } else if (amf_type == AMF_DATA_TYPE_NUMBER) { snprintf(str_val, sizeof(str_val), "%.f", num_val); av_dict_set(&s->metadata, key, str_val, 0); - } else if (amf_type == AMF_DATA_TYPE_STRING) + } else if (amf_type == AMF_DATA_TYPE_STRING) { av_dict_set(&s->metadata, key, str_val, 0); + } else if (amf_type == AMF_DATA_TYPE_DATE) { + time_t time; + struct tm t; + char datestr[128]; + time = date.milliseconds / 1000; // to seconds + localtime_r(&time, &t); + strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S %z", &t); + + av_dict_set(&s->metadata, key, datestr, 0); + } } return 0; @@ -683,7 +731,7 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) if (!strcmp(buffer, "onCaptionInfo")) return TYPE_ONCAPTIONINFO; - if (strcmp(buffer, "onMetaData") && strcmp(buffer, "onCuePoint")) { + if (strcmp(buffer, "onMetaData") && strcmp(buffer, "onCuePoint") && strcmp(buffer, "|RtmpSampleAccess")) { av_log(s, AV_LOG_DEBUG, "Unknown type %s\n", buffer); return TYPE_UNKNOWN; } @@ -699,8 +747,7 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) astream = stream; if (flv->last_keyframe_stream_index == -1) flv->last_keyframe_stream_index = i; - } - else if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) + } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) dstream = stream; } @@ -718,6 +765,10 @@ static int flv_read_header(AVFormatContext *s) int offset; int pre_tag_size = 0; + /* Actual FLV data at 0xe40000 in KUX file */ + if(!strcmp(s->iformat->name, "kux")) + avio_skip(s->pb, 0xe40000); + avio_skip(s->pb, 4); flags = avio_r8(s->pb); @@ -758,12 +809,12 @@ static int flv_read_close(AVFormatContext *s) static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size) { + int ret; if (!size) return 0; - av_freep(&st->codecpar->extradata); - if (ff_get_extradata(s, st->codecpar, s->pb, size) < 0) - return AVERROR(ENOMEM); + if ((ret = ff_get_extradata(s, st->codecpar, s->pb, size)) < 0) + return ret; st->internal->need_context_update = 1; return 0; } @@ -793,17 +844,23 @@ static void clear_index_entries(AVFormatContext *s, int64_t pos) AVStream *st = s->streams[i]; /* Remove all index entries that point to >= pos */ out = 0; - for (j = 0; j < st->nb_index_entries; j++) - if (st->index_entries[j].pos < pos) - st->index_entries[out++] = st->index_entries[j]; - st->nb_index_entries = out; + for (j = 0; j < st->internal->nb_index_entries; j++) + if (st->internal->index_entries[j].pos < pos) + st->internal->index_entries[out++] = st->internal->index_entries[j]; + st->internal->nb_index_entries = out; } } -static int amf_skip_tag(AVIOContext *pb, AMFDataType type) +static int amf_skip_tag(AVIOContext *pb, AMFDataType type, int depth) { int nb = -1, ret, parse_name = 1; + if (depth > MAX_DEPTH) + return AVERROR_PATCHWELCOME; + + if (avio_feof(pb)) + return AVERROR_EOF; + switch (type) { case AMF_DATA_TYPE_NUMBER: avio_skip(pb, 8); @@ -818,6 +875,8 @@ static int amf_skip_tag(AVIOContext *pb, AMFDataType type) parse_name = 0; case AMF_DATA_TYPE_MIXEDARRAY: nb = avio_rb32(pb); + if (nb < 0) + return AVERROR_INVALIDDATA; case AMF_DATA_TYPE_OBJECT: while(!pb->eof_reached && (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY)) { if (parse_name) { @@ -828,7 +887,7 @@ static int amf_skip_tag(AVIOContext *pb, AMFDataType type) } avio_skip(pb, size); } - if ((ret = amf_skip_tag(pb, avio_r8(pb))) < 0) + if ((ret = amf_skip_tag(pb, avio_r8(pb), depth + 1)) < 0) return ret; } break; @@ -872,7 +931,7 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt, else break; } else { - if ((ret = amf_skip_tag(pb, type)) < 0) + if ((ret = amf_skip_tag(pb, type, 0)) < 0) goto skip; } } @@ -966,144 +1025,141 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) retry: /* pkt size is repeated at end. skip it */ - pos = avio_tell(s->pb); - type = (avio_r8(s->pb) & 0x1F); - orig_size = - size = avio_rb24(s->pb); - flv->sum_flv_tag_size += size + 11; - dts = avio_rb24(s->pb); - dts |= (unsigned)avio_r8(s->pb) << 24; - av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb)); - if (avio_feof(s->pb)) - return AVERROR_EOF; - avio_skip(s->pb, 3); /* stream id, always 0 */ - flags = 0; - - if (flv->validate_next < flv->validate_count) { - int64_t validate_pos = flv->validate_index[flv->validate_next].pos; - if (pos == validate_pos) { - if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <= - VALIDATE_INDEX_TS_THRESH) { - flv->validate_next++; - } else { - clear_index_entries(s, validate_pos); - flv->validate_count = 0; - } - } else if (pos > validate_pos) { + pos = avio_tell(s->pb); + type = (avio_r8(s->pb) & 0x1F); + orig_size = + size = avio_rb24(s->pb); + flv->sum_flv_tag_size += size + 11; + dts = avio_rb24(s->pb); + dts |= (unsigned)avio_r8(s->pb) << 24; + av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb)); + if (avio_feof(s->pb)) + return AVERROR_EOF; + avio_skip(s->pb, 3); /* stream id, always 0 */ + flags = 0; + + if (flv->validate_next < flv->validate_count) { + int64_t validate_pos = flv->validate_index[flv->validate_next].pos; + if (pos == validate_pos) { + if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <= + VALIDATE_INDEX_TS_THRESH) { + flv->validate_next++; + } else { clear_index_entries(s, validate_pos); flv->validate_count = 0; } + } else if (pos > validate_pos) { + clear_index_entries(s, validate_pos); + flv->validate_count = 0; } + } - if (size == 0) { - ret = FFERROR_REDO; - goto leave; - } + if (size == 0) { + ret = FFERROR_REDO; + goto leave; + } - next = size + avio_tell(s->pb); - - if (type == FLV_TAG_TYPE_AUDIO) { - stream_type = FLV_STREAM_TYPE_AUDIO; - flags = avio_r8(s->pb); - size--; - } else if (type == FLV_TAG_TYPE_VIDEO) { - stream_type = FLV_STREAM_TYPE_VIDEO; - flags = avio_r8(s->pb); - size--; - if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) - goto skip; - } else if (type == FLV_TAG_TYPE_META) { - stream_type=FLV_STREAM_TYPE_SUBTITLE; - if (size > 13 + 1 + 4) { // Header-type metadata stuff - int type; - meta_pos = avio_tell(s->pb); - type = flv_read_metabody(s, next); - if (type == 0 && dts == 0 || type < 0) { - if (type < 0 && flv->validate_count && - flv->validate_index[0].pos > next && - flv->validate_index[0].pos - 4 < next - ) { - av_log(s, AV_LOG_WARNING, "Adjusting next position due to index mismatch\n"); - next = flv->validate_index[0].pos - 4; - } - goto skip; - } else if (type == TYPE_ONTEXTDATA) { - avpriv_request_sample(s, "OnTextData packet"); - return flv_data_packet(s, pkt, dts, next); - } else if (type == TYPE_ONCAPTION) { - return flv_data_packet(s, pkt, dts, next); - } else if (type == TYPE_UNKNOWN) { - stream_type = FLV_STREAM_TYPE_DATA; + next = size + avio_tell(s->pb); + + if (type == FLV_TAG_TYPE_AUDIO) { + stream_type = FLV_STREAM_TYPE_AUDIO; + flags = avio_r8(s->pb); + size--; + } else if (type == FLV_TAG_TYPE_VIDEO) { + stream_type = FLV_STREAM_TYPE_VIDEO; + flags = avio_r8(s->pb); + size--; + if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) + goto skip; + } else if (type == FLV_TAG_TYPE_META) { + stream_type=FLV_STREAM_TYPE_SUBTITLE; + if (size > 13 + 1 + 4) { // Header-type metadata stuff + int type; + meta_pos = avio_tell(s->pb); + type = flv_read_metabody(s, next); + if (type == 0 && dts == 0 || type < 0) { + if (type < 0 && flv->validate_count && + flv->validate_index[0].pos > next && + flv->validate_index[0].pos - 4 < next) { + av_log(s, AV_LOG_WARNING, "Adjusting next position due to index mismatch\n"); + next = flv->validate_index[0].pos - 4; } - avio_seek(s->pb, meta_pos, SEEK_SET); - } - } else { - av_log(s, AV_LOG_DEBUG, - "Skipping flv packet: type %d, size %d, flags %d.\n", - type, size, flags); -skip: - if (avio_seek(s->pb, next, SEEK_SET) != next) { - // This can happen if flv_read_metabody above read past - // next, on a non-seekable input, and the preceding data has - // been flushed out from the IO buffer. - av_log(s, AV_LOG_ERROR, "Unable to seek to the next packet\n"); - return AVERROR_INVALIDDATA; + goto skip; + } else if (type == TYPE_ONTEXTDATA) { + avpriv_request_sample(s, "OnTextData packet"); + return flv_data_packet(s, pkt, dts, next); + } else if (type == TYPE_ONCAPTION) { + return flv_data_packet(s, pkt, dts, next); + } else if (type == TYPE_UNKNOWN) { + stream_type = FLV_STREAM_TYPE_DATA; } - ret = FFERROR_REDO; - goto leave; - } - - /* skip empty data packets */ - if (!size) { - ret = FFERROR_REDO; - goto leave; + avio_seek(s->pb, meta_pos, SEEK_SET); } - - /* now find stream */ - for (i = 0; i < s->nb_streams; i++) { - st = s->streams[i]; - if (stream_type == FLV_STREAM_TYPE_AUDIO) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && - (s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags))) - break; - } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - (s->video_codec_id || flv_same_video_codec(st->codecpar, flags))) - break; - } else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) - break; - } else if (stream_type == FLV_STREAM_TYPE_DATA) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) - break; - } + } else { + av_log(s, AV_LOG_DEBUG, + "Skipping flv packet: type %d, size %d, flags %d.\n", + type, size, flags); +skip: + if (avio_seek(s->pb, next, SEEK_SET) != next) { + // This can happen if flv_read_metabody above read past + // next, on a non-seekable input, and the preceding data has + // been flushed out from the IO buffer. + av_log(s, AV_LOG_ERROR, "Unable to seek to the next packet\n"); + return AVERROR_INVALIDDATA; } - if (i == s->nb_streams) { - static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_DATA}; - st = create_stream(s, stream_types[stream_type]); - if (!st) - return AVERROR(ENOMEM); + ret = FFERROR_REDO; + goto leave; + } - } - av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard); + /* skip empty data packets */ + if (!size) { + ret = FFERROR_REDO; + goto leave; + } - if (flv->time_pos <= pos) { - dts += flv->time_offset; + /* now find stream */ + for (i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + if (stream_type == FLV_STREAM_TYPE_AUDIO) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + (s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags))) + break; + } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + (s->video_codec_id || flv_same_video_codec(st->codecpar, flags))) + break; + } else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) + break; + } else if (stream_type == FLV_STREAM_TYPE_DATA) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) + break; } + } + if (i == s->nb_streams) { + static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_DATA}; + st = create_stream(s, stream_types[stream_type]); + if (!st) + return AVERROR(ENOMEM); + } + av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard); - if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && - ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || - stream_type == FLV_STREAM_TYPE_AUDIO)) - av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME); + if (flv->time_pos <= pos) { + dts += flv->time_offset; + } - if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO))) - ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO))) - || st->discard >= AVDISCARD_ALL - ) { - avio_seek(s->pb, next, SEEK_SET); - ret = FFERROR_REDO; - goto leave; - } + if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && + ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || + stream_type == FLV_STREAM_TYPE_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 || stream_type == FLV_STREAM_TYPE_AUDIO)) || + (st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && stream_type == FLV_STREAM_TYPE_VIDEO)) || + st->discard >= AVDISCARD_ALL) { + avio_seek(s->pb, next, SEEK_SET); + ret = FFERROR_REDO; + goto leave; + } // if not streamed and no duration from metadata then seek to end to find // the duration from the timestamps @@ -1124,7 +1180,7 @@ retry_duration: avio_seek(s->pb, fsize - 3 - size, SEEK_SET); if (size == avio_rb24(s->pb) + 11) { uint32_t ts = avio_rb24(s->pb); - ts |= avio_r8(s->pb) << 24; + ts |= (unsigned)avio_r8(s->pb) << 24; if (ts) s->duration = ts * (int64_t)AV_TIME_BASE / 1000; else if (fsize >= 8 && fsize - 8 >= size) { @@ -1197,7 +1253,7 @@ retry_duration: if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4) { // sign extension int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000; - pts = dts + cts; + pts = av_sat_add64(dts, cts); if (cts < 0) { // dts might be wrong if (!flv->wrong_dts) av_log(s, AV_LOG_WARNING, @@ -1227,22 +1283,6 @@ retry_duration: if (st->codecpar->codec_id == AV_CODEC_ID_AAC && t && !strcmp(t->value, "Omnia A/XE")) st->codecpar->extradata_size = 2; - if (st->codecpar->codec_id == AV_CODEC_ID_AAC && 0) { - MPEG4AudioConfig cfg; - - if (avpriv_mpeg4audio_get_config(&cfg, st->codecpar->extradata, - st->codecpar->extradata_size * 8, 1) >= 0) { - st->codecpar->channels = cfg.channels; - st->codecpar->channel_layout = 0; - if (cfg.ext_sample_rate) - st->codecpar->sample_rate = cfg.ext_sample_rate; - else - st->codecpar->sample_rate = cfg.sample_rate; - av_log(s, AV_LOG_TRACE, "mp4a config channels %d sample rate %d\n", - st->codecpar->channels, st->codecpar->sample_rate); - } - } - ret = FFERROR_REDO; goto leave; } @@ -1262,12 +1302,11 @@ retry_duration: pkt->stream_index = st->index; pkt->pos = pos; if (flv->new_extradata[stream_type]) { - uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, - flv->new_extradata_size[stream_type]); - if (side) { - memcpy(side, flv->new_extradata[stream_type], - flv->new_extradata_size[stream_type]); - av_freep(&flv->new_extradata[stream_type]); + int ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, + flv->new_extradata[stream_type], + flv->new_extradata_size[stream_type]); + if (ret >= 0) { + flv->new_extradata[stream_type] = NULL; flv->new_extradata_size[stream_type] = 0; } } @@ -1279,10 +1318,10 @@ retry_duration: ff_add_param_change(pkt, channels, 0, sample_rate, 0, 0); } - if ( stream_type == FLV_STREAM_TYPE_AUDIO || - ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY) || - stream_type == FLV_STREAM_TYPE_SUBTITLE || - stream_type == FLV_STREAM_TYPE_DATA) + if (stream_type == FLV_STREAM_TYPE_AUDIO || + (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || + stream_type == FLV_STREAM_TYPE_SUBTITLE || + stream_type == FLV_STREAM_TYPE_DATA) pkt->flags |= AV_PKT_FLAG_KEY; leave: @@ -1366,3 +1405,23 @@ AVInputFormat ff_live_flv_demuxer = { .priv_class = &live_flv_class, .flags = AVFMT_TS_DISCONT }; + +static const AVClass kux_class = { + .class_name = "kuxdec", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_kux_demuxer = { + .name = "kux", + .long_name = NULL_IF_CONFIG_SMALL("KUX (YouKu)"), + .priv_data_size = sizeof(FLVContext), + .read_probe = kux_probe, + .read_header = flv_read_header, + .read_packet = flv_read_packet, + .read_seek = flv_read_seek, + .read_close = flv_read_close, + .extensions = "kux", + .priv_class = &kux_class, +};