[FFmpeg-devel,v9] lavf/flv: Add XV (Xunlei Video) Support. fixes ticket #3720

Submitted by Shivam Goyal on May 10, 2019, 1:10 p.m.

Details

Message ID 7bf175ae667e87af2088e40ae855dcd6@iitk.ac.in
State New
Headers show

Commit Message

Shivam Goyal May 10, 2019, 1:10 p.m.
The patch is for ticket #3720. XV Xunlei video support. XV video is a
flv video. The flv data starts from 0x200000th byte and the next 0x400
bytes are rotated, to find the value by which the next 0x400 bytes are
rotated. I subtracted the 0x200000th byte from 0x46 ( 'F' ) ( As every
flv video starts from 'FLV' signature, So, i already know the original
0x200000th byte), So, i got the value by which the next 0x400 bytes are
rotated. In the below patch i have skipped the first packet, so that i
don't have to decrypt the encrypted 0x400 bytes. 

But i also tried to decrypt the 0x400 bytes from that rot value. but
every time i try i reached at two situations: Either this becomes too
low level ( needs modifications of the avio stuff, which a demuxer
should not do). Or it affects the flv demuxer, like adding too many 'if
else' statements to the flv_read_packet() would slow demuxing of flv
format too, which i don't want. The ways i tried - 

-> Checking if the format is xv or flv every time it reads from input
file (decrypt it if needed). 

-> decrypt the input buffer at the time of reading header 

-> Making two avio contexts and one calling the other ( I am not sure if
i implemented it in the right way, but still i reached low level ). 

In the patch i have skipped the first packet due to this it can't tell
the rate and duration of video but it plays and can be converted with no
errors. 

Please review if it is right,or there can be another approach ( i know
this is an easy task but just due to those 0x400 bytes it is tricky ). 

Thank you, 

Shivam Goyal

Comments

Reimar Döffinger May 10, 2019, 9:51 p.m.
On 10.05.2019, at 15:10, Shivam Goyal <shivgo@iitk.ac.in> wrote:

> 
> -> Making two avio contexts and one calling the other ( I am not sure if
> i implemented it in the right way, but still i reached low level ). 

Can't you at least figure out the header size, decrypt the header and pass that to the normal header parsing code?
Even if not, I'd at least suggest changing the code from reading bytewise and applying rot
to reading all 8 bytes in a buffer, use a loop to apply rot and then the standard AV_RL functions to read the 32 and 24 bit values.
Shivam Goyal May 11, 2019, 4:13 a.m.
On 11-05-2019 03:21, Reimar Döffinger wrote:

> On 10.05.2019, at 15:10, Shivam Goyal <shivgo@iitk.ac.in> wrote:
> 
>> -> Making two avio contexts and one calling the other ( I am not sure if
>> i implemented it in the right way, but still i reached low level ).
> 
> Can't you at least figure out the header size, decrypt the header and pass that to the normal header parsing code?

  I can get the header size. but the problem is with the first flv
packet. which should be parsed by the flv_read_packet and which is
taking AVFormatContaxt as argument and reads from the file with avio*
functions. 

> Even if not, I'd at least suggest changing the code from reading bytewise and applying rot
> to reading all 8 bytes in a buffer, use a loop to apply rot and then the standard AV_RL functions to read the 32 and 24 bit values.

If i understood correctly, i think this is exactly the same approach
which i already took in decrypting the filled buffer. but the code
become low level because it modifies the buffer, which a demuxer should
not do. 

Thanks for the review 
Shivam Goyal

Patch hide | download patch | download mbox

From b9dde21af273c8137df370399ade79c0c59a4046 Mon Sep 17 00:00:00 2001
From: Shivam Goyal <shivamgoyal1506@outlook.com>
Date: Fri, 10 May 2019 17:53:26 +0530
Subject: [PATCH] lavf/flv: Add XV(Xunlei video file) support, fixes ticket
 #3720

---
 Changelog                |  1 +
 libavformat/Makefile     |  1 +
 libavformat/allformats.c |  1 +
 libavformat/flvdec.c     | 74 ++++++++++++++++++++++++++++++++++++++++
 libavformat/version.h    |  4 +--
 5 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/Changelog b/Changelog
index a3fa0c14a2..a9dc982d08 100644
--- a/Changelog
+++ b/Changelog
@@ -26,6 +26,7 @@  version <next>:
 - lscr decoder
 - lagfun filter
 - asoftclip filter
+- XV (Xunlei Video) demuxer
 
 
 version 4.1:
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 99be60d184..e090c051f1 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -561,6 +561,7 @@  OBJS-$(CONFIG_WV_MUXER)                  += wvenc.o wv.o apetag.o img2.o
 OBJS-$(CONFIG_XA_DEMUXER)                += xa.o
 OBJS-$(CONFIG_XBIN_DEMUXER)              += bintext.o sauce.o
 OBJS-$(CONFIG_XMV_DEMUXER)               += xmv.o
+OBJS-$(CONFIG_XV_DEMUXER)                += flvdec.o
 OBJS-$(CONFIG_XVAG_DEMUXER)              += xvag.o
 OBJS-$(CONFIG_XWMA_DEMUXER)              += xwma.o
 OBJS-$(CONFIG_YOP_DEMUXER)               += yop.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index d316a0529a..b499186071 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -456,6 +456,7 @@  extern AVOutputFormat ff_wv_muxer;
 extern AVInputFormat  ff_xa_demuxer;
 extern AVInputFormat  ff_xbin_demuxer;
 extern AVInputFormat  ff_xmv_demuxer;
+extern AVInputFormat  ff_xv_demuxer;
 extern AVInputFormat  ff_xvag_demuxer;
 extern AVInputFormat  ff_xwma_demuxer;
 extern AVInputFormat  ff_yop_demuxer;
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index b531a39adc..87bfb68ee5 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -127,6 +127,19 @@  static int kux_probe(const AVProbeData *p)
     return 0;
 }
 
+static int xv_probe(const AVProbeData *p)
+{
+    const uint8_t *d = p->buf;
+
+    if (d[0] == 'X' &&
+        d[1] == 'L' &&
+        d[2] == 'V' &&
+        d[3] == 'F') {
+        return AVPROBE_SCORE_EXTENSION + 1;
+    }
+    return 0;
+}
+
 static void add_keyframes_index(AVFormatContext *s)
 {
     FLVContext *flv   = s->priv_data;
@@ -783,6 +796,46 @@  static int flv_read_header(AVFormatContext *s)
     return 0;
 }
 
+static int xv_read_header(AVFormatContext *s)
+{
+    int flags;
+    FLVContext *xv = s->priv_data;
+    AVIOContext *ic = s->pb;
+    int offset;
+    int enc_tag_size;
+    int rot;
+
+    // Find rot for rotating the bytes
+    avio_skip(ic, 0x200000);
+    rot = 0x46 - avio_r8(ic);
+
+    avio_skip(ic, 3);
+
+    flags = (avio_r8(ic) + rot) & 0xff;
+
+    xv->missing_streams = flags & (FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO);
+
+    s->ctx_flags |= AVFMTCTX_NOHEADER;
+
+    offset = ((avio_r8(ic) + rot & 0xff) << 24 |
+              (avio_r8(ic) + rot & 0xff) << 16 |
+              (avio_r8(ic) + rot & 0xff) << 8 |
+              (avio_r8(ic) + rot & 0xff)) + 0x200000;
+    avio_seek(ic, offset + 5, SEEK_SET);
+
+    enc_tag_size = ((avio_r8(ic) + rot & 0xff) << 16 |
+                    (avio_r8(ic) + rot & 0xff) << 8 |
+                    (avio_r8(ic) + rot & 0xff));
+    // Skip encoded data
+    avio_skip(ic, enc_tag_size + 11);
+
+    s->start_time = 0;
+    xv->sum_flv_tag_size = 0;
+    xv->last_keyframe_stream_index = -1;
+
+    return 0;
+}
+
 static int flv_read_close(AVFormatContext *s)
 {
     int i;
@@ -1424,3 +1477,24 @@  AVInputFormat ff_kux_demuxer = {
     .extensions     = "kux",
     .priv_class     = &kux_class,
 };
+
+static const AVClass xv_class = {
+    .class_name = "xvdec",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_xv_demuxer = {
+    .name           = "xv",
+    .long_name      = NULL_IF_CONFIG_SMALL("Xunlei(Thunder) Video File"),
+    .priv_data_size = sizeof(FLVContext),
+    .read_probe     = xv_probe,
+    .read_header    = xv_read_header,
+    .read_packet    = flv_read_packet,
+    .read_seek      = flv_read_seek,
+    .read_close     = flv_read_close,
+    .extensions     = "xv",
+    .priv_class     = &xv_class,
+    .flags          = AVFMT_TS_DISCONT
+};
diff --git a/libavformat/version.h b/libavformat/version.h
index 150a72e27d..52dd95f5c6 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,8 +32,8 @@ 
 // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
 // Also please add any ticket numbers that you believe might be affected here
 #define LIBAVFORMAT_VERSION_MAJOR  58
-#define LIBAVFORMAT_VERSION_MINOR  27
-#define LIBAVFORMAT_VERSION_MICRO 103
+#define LIBAVFORMAT_VERSION_MINOR  28
+#define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
-- 
2.21.0