[FFmpeg-devel] [PATCH 3/3] avformat/electronicarts: add option to return alpha channel in the main video stream in VP6A codec
Marton Balint
cus at passwd.hu
Sun Nov 13 20:44:41 EET 2022
Signed-off-by: Marton Balint <cus at passwd.hu>
---
doc/demuxers.texi | 18 ++++++++++++++++
libavformat/electronicarts.c | 42 +++++++++++++++++++++++++++++++-----
libavformat/version.h | 2 +-
3 files changed, 56 insertions(+), 6 deletions(-)
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
+ at section ea
+
+Electronic Arts Multimedia format demuxer.
+
+This format is used by various Electronic Arts games.
+
+ at subsection Options
+
+ at table @option
+
+ at 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.
+
+ at 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 <inttypes.h>
#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, \
--
2.35.3
More information about the ffmpeg-devel
mailing list