diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 2b6dd86c2a..f07f3f5318 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -285,6 +285,24 @@ This demuxer accepts the following option: @end table +@section ea + +Electronic Arts Multimedia format demuxer. + +This format is used by various Electronic Arts games. + +@subsection Options + +@table @option + +@item merge_alpha @var{bool} + +Normally the VP6 alpha channel (if exists) is returned as a secondary video +stream, by setting this option you can make the demuxer return a single video +stream which contains the alpha channel in addition to the ordinary video. + +@end table + @section imf Interoperable Master Format demuxer. diff --git a/libavformat/electronicarts.c b/libavformat/electronicarts.c index 0532264f38..e7f574aede 100644 --- a/libavformat/electronicarts.c +++ b/libavformat/electronicarts.c @@ -28,6 +28,7 @@ #include #include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" #include "avformat.h" #include "internal.h" @@ -75,6 +76,8 @@ typedef struct VideoProperties { } VideoProperties; typedef struct EaDemuxContext { + const AVClass *class; + int big_endian; VideoProperties video, alpha; @@ -88,6 +91,7 @@ typedef struct EaDemuxContext { int num_samples; int platform; + int merge_alpha; } EaDemuxContext; static uint32_t read_arbitrary(AVIOContext *pb) @@ -442,6 +446,10 @@ static int process_ea_header(AVFormatContext *s) case AVhd_TAG: err = process_video_header_vp6(s, &ea->alpha); + if (err >= 0 && ea->video.codec == AV_CODEC_ID_VP6 && ea->merge_alpha) { + ea->alpha.codec = 0; + ea->video.codec = AV_CODEC_ID_VP6A; + } break; } @@ -578,7 +586,7 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt) int partial_packet = 0; int hit_end = 0; unsigned int chunk_type, chunk_size; - int ret = 0, packet_read = 0, key = 0; + int ret = 0, packet_read = 0, key = 0, vp6a; int av_uninit(num_samples); while ((!packet_read && !hit_end) || partial_packet) { @@ -721,19 +729,28 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt) get_video_packet: if (!chunk_size) continue; + if (chunk_size > INT_MAX - 3) + return AVERROR_INVALIDDATA; + + vp6a = (ea->video.codec == AV_CODEC_ID_VP6A && (chunk_type == MV0F_TAG || chunk_type == MV0K_TAG)); if (partial_packet) { ret = av_append_packet(pb, pkt, chunk_size); - } else - ret = av_get_packet(pb, pkt, chunk_size); + } else { + if (vp6a) + avio_seek(pb, -3, SEEK_CUR); + ret = av_get_packet(pb, pkt, chunk_size + (vp6a ? 3 : 0)); + if (ret >= 0 && vp6a) + AV_WB24(pkt->data, chunk_size); + } packet_read = 1; if (ret < 0) { partial_packet = 0; break; } - partial_packet = chunk_type == MVIh_TAG; - if (chunk_type == AV0K_TAG || chunk_type == AV0F_TAG) + partial_packet = vp6a || chunk_type == MVIh_TAG; + if (ea->alpha.codec && (chunk_type == AV0K_TAG || chunk_type == AV0F_TAG)) pkt->stream_index = ea->alpha.stream_index; else pkt->stream_index = ea->video.stream_index; @@ -752,6 +769,20 @@ get_video_packet: return ret; } +#define OFFSET(x) offsetof(EaDemuxContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + {"merge_alpha", "return VP6 alpha in the main video stream", OFFSET(merge_alpha), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, + {NULL} +}; + +static const AVClass ea_class = { + .class_name = "ea demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + const AVInputFormat ff_ea_demuxer = { .name = "ea", .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts Multimedia"), @@ -759,4 +790,5 @@ const AVInputFormat ff_ea_demuxer = { .read_probe = ea_probe, .read_header = ea_read_header, .read_packet = ea_read_packet, + .priv_class = &ea_class, }; diff --git a/libavformat/version.h b/libavformat/version.h index 7c9d50b7b3..a7e5a9ac66 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ #include "version_major.h" #define LIBAVFORMAT_VERSION_MINOR 34 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MICRO 102 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \