[FFmpeg-devel] [PATCH] avformat: Add Dynacolor MVC Demuxer

Tom Needham 06needhamt at gmail.com
Sat May 16 17:22:56 EEST 2020


This demuxer adds support for demuxing files in the Dynacolor format
such as the sample located at:

http://samples.ffmpeg.org/camera-dvr/dynacolor/dynacolor-camera-sample

However some decode errors are showing on the resulting MPEG4 stream.
I don't know whether this is a bug with the demuxer or the file as there is only one sample
but the output results in a 1 second mp4 file that is playable in VLC media player.

Signed-off-by: Tom Needham <06needhamt at gmail.com>
---
 Changelog                |   1 +
 doc/general.texi         |   1 +
 libavformat/Makefile     |   1 +
 libavformat/allformats.c |   1 +
 libavformat/dynacolor.c  | 411 +++++++++++++++++++++++++++++++++++++++
 libavformat/dynacolor.h  | 209 ++++++++++++++++++++
 libavformat/version.h    |   2 +-
 7 files changed, 625 insertions(+), 1 deletion(-)
 create mode 100644 libavformat/dynacolor.c
 create mode 100644 libavformat/dynacolor.h

diff --git a/Changelog b/Changelog
index 711861bda9..79d39494c9 100644
--- a/Changelog
+++ b/Changelog
@@ -54,6 +54,7 @@ version <next>:
 - DERF demuxer
 - CRI HCA decoder
 - CRI HCA demuxer
+- Dynacolor MVC Demuxer
 
 
 version 4.2:
diff --git a/doc/general.texi b/doc/general.texi
index 752618a00b..4eb4716d87 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -452,6 +452,7 @@ library:
 @item DXA                       @tab   @tab X
     @tab This format is used in the non-Windows version of the Feeble Files
          game and different game cutscenes repacked for use with ScummVM.
+ at item Dynacolor MVC             @tab   @tab X
 @item Electronic Arts cdata  @tab    @tab X
 @item Electronic Arts Multimedia  @tab    @tab X
     @tab Used in various EA games; files have extensions like WVE and UV2.
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 8fd0d43721..4d1ca8b7ed 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -169,6 +169,7 @@ OBJS-$(CONFIG_DV_MUXER)                  += dvenc.o
 OBJS-$(CONFIG_DVBSUB_DEMUXER)            += dvbsub.o rawdec.o
 OBJS-$(CONFIG_DVBTXT_DEMUXER)            += dvbtxt.o rawdec.o
 OBJS-$(CONFIG_DXA_DEMUXER)               += dxa.o
+OBJS-$(CONFIG_DYNACOLOR_DEMUXER)         += dynacolor.o
 OBJS-$(CONFIG_EA_CDATA_DEMUXER)          += eacdata.o
 OBJS-$(CONFIG_EA_DEMUXER)                += electronicarts.o
 OBJS-$(CONFIG_EAC3_DEMUXER)              += ac3dec.o rawdec.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 39d2c352f5..50f3926b05 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -131,6 +131,7 @@ extern AVOutputFormat ff_dv_muxer;
 extern AVInputFormat  ff_dvbsub_demuxer;
 extern AVInputFormat  ff_dvbtxt_demuxer;
 extern AVInputFormat  ff_dxa_demuxer;
+extern AVInputFormat  ff_dynacolor_demuxer;
 extern AVInputFormat  ff_ea_demuxer;
 extern AVInputFormat  ff_ea_cdata_demuxer;
 extern AVInputFormat  ff_eac3_demuxer;
diff --git a/libavformat/dynacolor.c b/libavformat/dynacolor.c
new file mode 100644
index 0000000000..05a32b5299
--- /dev/null
+++ b/libavformat/dynacolor.c
@@ -0,0 +1,411 @@
+/*
+ * Dynacolor MVC Demuxer
+ * Copyright (c) 2020 Tom Needham
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <time.h>
+#include "avformat.h"
+#include "internal.h"
+#include "dynacolor.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/timecode.h"
+#include "libavutil/avassert.h"
+
+int ff_dyna_read_packet_header(AVFormatContext *ctx, AVIOContext *pb, unsigned char *pes_data, DynacolorPesHeader *pes,
+                      unsigned int *size, time_t *time, DynacolorHeader *header, unsigned int *basicIdx_H, unsigned int *basicIdx_L,
+                       unsigned char first)
+{
+    int ret = 0;
+    unsigned int stream_format;
+
+    *(basicIdx_H) = avio_rl32(pb);
+
+    header->Basic.Header1    = *(basicIdx_H)&0xFF;
+    header->Basic.Header2    = *(basicIdx_H) >> 8 & 0xFF;
+    header->Basic.reserved   = *(basicIdx_H) >> 16 & 0x0F;
+    header->Basic.Source     = *(basicIdx_H) >> 20 & 0x01;
+    header->Basic.WidthBase  = *(basicIdx_H) >> 21 & 0x03;
+    header->Basic.Reserved0  = *(basicIdx_H) >> 23 & 0x01;
+    header->Basic.Channel    = *(basicIdx_H) >> 24 & 0x02;
+    header->Basic.StreamType = *(basicIdx_H) >> 26 & 0x02;
+    header->Basic.QI         = *(basicIdx_H) >> 28 & 0x0F;
+
+    *size = avio_rl32(pb);
+    header->Basic.Size = *size;
+
+    *time = (time_t)avio_rl32(pb);
+    header->Basic.Time = ((unsigned int) *time);
+
+    *(basicIdx_L) = avio_rl32(pb);
+
+    header->Basic.NTSC_PAL    = *(basicIdx_L)&0x01;
+    header->Basic.ImgMode     = *(basicIdx_L) >> 1 & 0x01;
+    header->Basic.Audio       = *(basicIdx_L) >> 2 & 0x01;
+    header->Basic.DST         = *(basicIdx_L) >> 3 & 0x01;
+    header->Basic.Covert      = *(basicIdx_L) >> 4 & 0x01;
+    header->Basic.Vloss       = *(basicIdx_L) >> 5 & 0x01;
+    header->Basic.AlarmIn     = *(basicIdx_L) >> 6 & 0x01;
+    header->Basic.Motion      = *(basicIdx_L) >> 7 & 0x01;
+    header->Basic.ExtraEnable = *(basicIdx_L) >> 8 & 0x01;
+    header->Basic.EventEnable = *(basicIdx_L) >> 9 & 0x01;
+    header->Basic.PPS         = *(basicIdx_L) >> 10 & 0x40;
+    header->Basic.Type        = *(basicIdx_L) >> 16 & 0x08;
+    header->Basic.Channel     = *(basicIdx_L) >> 19 & 0x20;
+    header->Basic.Chksum      = *(basicIdx_L) >> 24 & 0xFF;
+
+    if (header->Basic.ExtraEnable) {
+        // File has DynacolorExtraIdx header so parse it
+        unsigned int start;
+        unsigned char end;
+        char checksum;
+
+        start = avio_rl32(pb);
+
+        header->Extra.IsDST_S_W      = start & 0x01;
+        header->Extra.DST_Minutes    = start >> 1 & 0xFF;
+        header->Extra.OverSpeed      = start >> 9 & 0x01;
+        header->Extra.SkipPicCnt     = start >> 10 & 0x20;
+        header->Extra.Exception      = start >> 15 & 0x01;
+        header->Extra.SuperExtraSize = start >> 16 & 0xFFFF;
+
+        header->Extra.Serno     = avio_rl32(pb);
+        header->Extra.AlmIn[0]  = (unsigned char)avio_r8(pb);
+        header->Extra.AlmIn[1]  = (unsigned char)avio_r8(pb);
+        header->Extra.Vloss[0]  = (unsigned char)avio_r8(pb);
+        header->Extra.Vloss[1]  = (unsigned char)avio_r8(pb);
+        header->Extra.Motion[0] = (unsigned char)avio_r8(pb);
+        header->Extra.Motion[1] = (unsigned char)avio_r8(pb);
+
+        end = (unsigned char)avio_r8(pb);
+
+        header->Extra.IsDVRRec = end & 0x03;
+        header->Extra.TimeZone = (end >> 2) & 0x40;
+
+        checksum = (char)avio_r8(pb);
+
+        header->Basic.Chksum = checksum & 0xFF;
+
+        header->SuperExtra.type        = (int)avio_rl32(pb);
+        header->SuperExtra.remain_size = (int)avio_rl32(pb);
+
+        if (avio_read(pb, header->SuperExtra.title, DYNACOLOR_SUPEREXTRA_TITLE_SIZE) != DYNACOLOR_SUPEREXTRA_TITLE_SIZE)
+            return AVERROR_INVALIDDATA;
+
+        if (avio_read(pb, header->SuperExtra.extra_data, DYNACOLOR_SUPEREXTRA_EXTRA_DATA_SIZE) != DYNACOLOR_SUPEREXTRA_EXTRA_DATA_SIZE)
+            return AVERROR_INVALIDDATA;
+
+    } else {
+        // File has no DynacolorExtraIdx header so skip it
+        av_log(ctx, AV_LOG_DEBUG, "Skipping DynacolorExtraIdx and DynacolorSuperExtraIdx Header\n");
+        avio_skip(pb, DYNACOLOR_EXTRA_SIZE + DYNACOLOR_SUPEREXTRA_SIZE);
+
+        memset(&header->Extra, 0xFF, DYNACOLOR_EXTRA_SIZE);
+        memset(&header->SuperExtra, 0xFF, DYNACOLOR_SUPEREXTRA_SIZE);
+    }
+
+    if (avio_read(pb, pes_data, DYNACOLOR_PES_HEADER_SIZE) != DYNACOLOR_PES_HEADER_SIZE)
+        return AVERROR_INVALIDDATA;
+
+    ret = ff_dyna_build_pes_header(ctx, pes_data);
+
+    if (ret) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to Build PES Header\n");
+        return AVERROR_INVALIDDATA;
+    } else {
+        if(first) {
+            stream_format = ff_dyna_get_stream_format(ctx, header);
+            if (!stream_format) {
+                avpriv_report_missing_feature(ctx, "Format %02X,", stream_format);
+                return AVERROR_PATCHWELCOME;
+            } else if (stream_format == AVERROR_INVALIDDATA) {
+                av_log(ctx, AV_LOG_ERROR, "Could not Determine Stream Format\n");
+                return AVERROR_INVALIDDATA;
+            }
+            av_log(ctx, AV_LOG_DEBUG, "File Has 0x%02X Stream Format\n", stream_format);
+        }
+    }
+
+    return ret;
+}
+
+int ff_dyna_get_stream_format(AVFormatContext *ctx, DynacolorHeader *header)
+{
+    DynacolorContext *priv = ctx->priv_data;
+    int ret = 0;
+
+    // Try And Build Header for H264 Format
+    av_log(ctx, AV_LOG_DEBUG, "Validating H264 PES Header\n");
+    ret = ff_dyna_check_pes_packet_header(ctx, DYNACOLOR_H264_FORMAT_PREFIX);
+
+    if (!ret) {
+        // Format was not H264 so try And Build Header for MPEG4 Format
+        av_log(ctx, AV_LOG_DEBUG, "Validating MPEG4 PES Header\n");
+        ret = ff_dyna_check_pes_packet_header(ctx, DYNACOLOR_MPEG4_FORMAT_PREFIX);
+
+        if (!ret) {
+            // Format was not MPEG4 or H264 so try And Build Header for JPEG Format
+            av_log(ctx, AV_LOG_DEBUG, "Validating JPEG PES Header\n");
+            ret = ff_dyna_check_pes_packet_header(ctx, DYNACOLOR_JPEG_FORMAT_PREFIX);
+
+            if (!ret) {
+                // Format was not MPEG4 or H264 or JPEG so try And Build Header for AUDIO Format
+                av_log(ctx, AV_LOG_DEBUG, "Validating AUDIO PES Header\n");
+                ret = ff_dyna_check_pes_packet_header(ctx, DYNACOLOR_AUDIO_FORMAT_PREFIX);
+
+                if (!ret) {
+                    avpriv_report_missing_feature(ctx, "Format %02X,", priv->pes_header.format_id);
+                    return AVERROR_PATCHWELCOME;
+                } else {
+                    av_log(ctx, AV_LOG_DEBUG, "Successfully Validated AUDIO PES Header\n");
+                    return DYNACOLOR_JPEG_FORMAT_PREFIX;
+                }
+            } else {
+                av_log(ctx, AV_LOG_DEBUG, "Successfully Validated JPEG PES Header\n");
+                return DYNACOLOR_JPEG_FORMAT_PREFIX;
+            }
+        } else {
+            av_log(ctx, AV_LOG_DEBUG, "Successfully Validated MPEG4 PES Header\n");
+            return DYNACOLOR_MPEG4_FORMAT_PREFIX;
+        }
+    } else {
+        av_log(ctx, AV_LOG_DEBUG, "Successfully Validated H264 PES Header\n");
+        return DYNACOLOR_H264_FORMAT_PREFIX;
+    }
+
+    return 0;
+}
+
+int ff_dyna_build_pes_header(AVFormatContext *ctx, uint8_t *pes_data)
+{
+    DynacolorContext *priv = ctx->priv_data;
+
+    priv->pes_header.start_code0 = pes_data[0];
+    priv->pes_header.start_code1 = pes_data[1];
+    priv->pes_header.start_code2 = pes_data[2];
+    priv->pes_header.format_id   = pes_data[3] & 0x0F;
+    priv->pes_header.channel_id  = pes_data[3] >> 8 & 0x0F;
+
+    priv->pes_header.unused_0 = MKTAG(pes_data[4], pes_data[5], pes_data[6], pes_data[7]);
+    priv->pes_header.unused_1 = MKTAG(pes_data[8], pes_data[9], pes_data[10], pes_data[11]);
+    priv->pes_header.unused_2 = MKTAG(pes_data[12], pes_data[13], pes_data[14], pes_data[15]);
+    priv->pes_header.unused_3 = MKTAG(pes_data[16], pes_data[17], pes_data[18], pes_data[19]);
+    priv->pes_header.unused_4 = MKTAG(pes_data[20], pes_data[21], pes_data[22], pes_data[23]);
+
+    priv->pes_header.size_bit7to0   = pes_data[24];
+    priv->pes_header.size_bit10to8  = pes_data[25] & 0x08;
+    priv->pes_header.size_bit14to11 = pes_data[26] & 0xF;
+    priv->pes_header.size_bit21to15 = pes_data[27];
+    priv->pes_header.size_marker0   = pes_data[28] & 0x01;
+    priv->pes_header.size_marker1   = pes_data[29] & 0x01;
+    priv->pes_header.picture_type   = pes_data[30];
+    priv->pes_header.is_interleaved = pes_data[31] & 0x01;
+    priv->pes_header.field_id       = pes_data[31] >> 1 & 0x03;
+
+    return 0;
+}
+
+int ff_dyna_check_pes_packet_header(AVFormatContext *ctx, int format_prefix)
+{
+    DynacolorContext *dyna = ctx->priv_data;
+    DynacolorPesHeader *pes = &dyna->pes_header;
+
+    return pes->format_id == format_prefix;
+}
+
+static int dyna_read_probe(const AVProbeData *p)
+{
+    int magic = MKTAG(p->buf[0], p->buf[1], p->buf[2], p->buf[3]);
+    
+    if (magic == 0x20103240)
+        return AVPROBE_SCORE_MAX;
+
+    return 0;
+}
+
+static int dyna_read_header(AVFormatContext *ctx)
+{
+    int ret = 0;
+    DynacolorContext *priv = ctx->priv_data;
+    AVIOContext *pb = ctx->pb;
+
+    AVStream *vstream = NULL;
+    AVCodec *vcodec = NULL;
+    AVCodecParameters *vcodec_params = NULL;
+
+    AVStream *astream = NULL;
+    AVCodec *acodec = NULL;
+    AVCodecParameters *acodec_params = NULL;
+
+    time_t time;
+    unsigned char *pes_data;
+    DynacolorPesHeader *pes;
+    unsigned int size;
+
+    unsigned int basicIdx_H, basicIdx_L;
+
+    pes_data = av_malloc_array(DYNACOLOR_PES_HEADER_SIZE, 1);
+    pes = av_malloc(sizeof(DynacolorPesHeader));
+
+    ret = ff_dyna_read_packet_header(ctx, pb, pes_data, pes, &size, &time,
+                            &priv->header, &basicIdx_H, &basicIdx_L, 1);
+
+    if (ret) {
+        ret = AVERROR_INVALIDDATA;
+        goto end;
+    }
+
+    if (priv->pes_header.format_id == DYNACOLOR_JPEG_FORMAT_PREFIX) {
+        av_log(ctx, AV_LOG_DEBUG, "Demuxing JPEG Video Stream\n");
+
+        vcodec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
+        vstream = avformat_new_stream(ctx, vcodec);
+        vcodec_params = vstream->codecpar;
+
+        if (!vstream || !vcodec_params) {
+            ret = AVERROR_INVALIDDATA;
+            goto end;
+        }
+
+    } else if (priv->pes_header.format_id == DYNACOLOR_MPEG4_FORMAT_PREFIX) {
+        av_log(ctx, AV_LOG_DEBUG, "Demuxing MPEG4 Video Stream\n");
+
+        vcodec = avcodec_find_decoder(AV_CODEC_ID_MPEG4);
+        vstream = avformat_new_stream(ctx, vcodec);
+        vcodec_params = vstream->codecpar;
+
+        if (!vstream || !vcodec_params) {
+            ret = AVERROR_INVALIDDATA;
+            goto end;
+        }
+
+    } else if (priv->pes_header.format_id == DYNACOLOR_H264_FORMAT_PREFIX) {
+        av_log(ctx, AV_LOG_DEBUG, "Demuxing H264 Video Stream\n");
+
+        vcodec = avcodec_find_decoder(AV_CODEC_ID_H264);
+        vstream = avformat_new_stream(ctx, vcodec);
+        vcodec_params = vstream->codecpar;
+
+        if (!vstream || !vcodec_params) {
+            ret = AVERROR_INVALIDDATA;
+            goto end;
+        }
+
+    } else if (priv->pes_header.format_id == DYNACOLOR_AUDIO_FORMAT_PREFIX) {
+        av_log(ctx, AV_LOG_DEBUG, "Demuxing Audio Stream\n");
+
+        acodec = avcodec_find_decoder(AV_CODEC_ID_PCM_F16LE);
+        astream = avformat_new_stream(ctx, acodec);
+        acodec_params = astream->codecpar;
+
+        if (!astream || !acodec_params) {
+            ret = AVERROR_INVALIDDATA;
+            goto end;
+        }
+    }
+
+end:
+    av_free(pes_data);
+    av_free(pes);
+    
+    return ret;
+}
+
+static int dyna_read_packet(AVFormatContext *ctx, AVPacket *pkt)
+{
+    int ret = 0;
+    DynacolorContext *priv = ctx->priv_data;
+    AVIOContext *pb = ctx->pb;
+    DynacolorPesHeader *pes;
+
+    time_t time;
+    unsigned char *pes_data;
+    unsigned char *pkt_data;
+    unsigned int size;
+
+    unsigned int basicIdx_H, basicIdx_L;
+
+    pes_data = av_malloc_array(DYNACOLOR_PES_HEADER_SIZE, 1);
+    pes = av_malloc(sizeof(DynacolorPesHeader));
+
+    ret = ff_dyna_read_packet_header(ctx, pb, pes_data, pes, &size, &time,
+                            &priv->header, &basicIdx_H, &basicIdx_L, 0);
+
+    size = (priv->pes_header.size_bit7to0 & 0xFF)
+        | ((priv->pes_header.size_bit10to8 & 0x04) << 15)
+        | ((priv->pes_header.size_bit14to11 & 0x08) << 11)
+        | ((priv->pes_header.size_bit21to15 & 0x7F) << 8);
+
+    pkt_data = av_malloc(size);
+    ret = avio_read(pb, pkt_data, size);
+
+    if (ret != size)
+        goto end;
+
+    ret = av_packet_from_data(pkt, pkt_data, size);
+
+    if (ret < 0) {
+        av_log(ctx, AV_LOG_ERROR, "Error Building Packet\n");
+        goto end;
+    }
+
+end:
+    av_free(pes_data);
+    av_free(pes);
+
+    return ret;
+}
+
+static int dyna_read_close(AVFormatContext *ctx)
+{
+    return 0;
+}
+
+static int dyna_read_seek(AVFormatContext *ctx, int stream_index,
+                        int64_t timestamp, int flags)
+{
+    DynacolorContext *priv = ctx->priv_data;
+    unsigned int size = 0;
+    int64_t ret = 0L;
+
+    size = (priv->pes_header.size_bit7to0 & 0xFF)
+        | ((priv->pes_header.size_bit10to8 & 0x04) << 15)
+        | ((priv->pes_header.size_bit14to11 & 0x08) << 11)
+        | ((priv->pes_header.size_bit21to15 & 0x7F) << 8);
+
+    ret = avio_seek(ctx->pb, size, SEEK_SET);
+
+    if(ret < 0)
+        return ret;
+
+    return 0;
+}
+
+AVInputFormat ff_dynacolor_demuxer = {
+    .name = "dynacolor",
+    .long_name = NULL_IF_CONFIG_SMALL("Dynacolor MVC"),
+    .priv_data_size = sizeof(DynacolorContext),
+    .read_probe = dyna_read_probe,
+    .read_header = dyna_read_header,
+    .read_packet = dyna_read_packet,
+    .read_close = dyna_read_close,
+    .read_seek = dyna_read_seek,
+    .extensions = "dyna,dyn",
+};
diff --git a/libavformat/dynacolor.h b/libavformat/dynacolor.h
new file mode 100644
index 0000000000..a620ed7a2e
--- /dev/null
+++ b/libavformat/dynacolor.h
@@ -0,0 +1,209 @@
+/*
+ * Dynacolor MVC Demuxer
+ * Copyright (c) 2020 Tom Needham
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_DYNACOLOR_H
+#define AVFORMAT_DYNACOLOR_H
+
+#include "avformat.h"
+
+// The data structure of the streaming video:
+// [16-byte DynacolorBasicIdx header] + [16-byte DynacolorExtraIdx header] + ['SuperExtraSize' bytes] + [32-byte PES header] + [video body]
+// The 'SuperExtraSize' is defined in the 'DynacolorExtraIdx' structure to store the additional information, and usually equals zero.
+
+#define DYNACOLOR_PES_HEADER_SIZE 32
+#define DYNACOLOR_EXTRA_SIZE 16
+#define DYNACOLOR_SUPEREXTRA_SIZE 108
+#define DYNACOLOR_SUPEREXTRA_TITLE_SIZE 12
+#define DYNACOLOR_SUPEREXTRA_EXTRA_DATA_SIZE 96
+
+#define DYNACOLOR_AUDIO_FORMAT_PREFIX 0x0C
+#define DYNACOLOR_MPEG4_FORMAT_PREFIX 0x0D
+#define DYNACOLOR_JPEG_FORMAT_PREFIX 0x0E
+#define DYNACOLOR_H264_FORMAT_PREFIX 0x0F
+
+// Big Endian
+// DG600 uses big-endian CPU
+
+// Basic Idx: 16 bytes
+typedef struct
+{
+    unsigned int Header1 : 8;   // [2] "@X" -- X:device type, DG600 is "6" @6
+    unsigned int Header2 : 8;   // [2] "@X" -- X:device type, DG600 is "6" @6
+    unsigned int reserved : 4;  // 4 bits
+    unsigned int Source : 1;    // 1 bit  : (0 - DVR, 1 - IP Dev)
+    unsigned int WidthBase : 2; // 0:720 , 1:704, 2:640
+    unsigned int Reserved0 : 1; // 1 bit  : (0 - Disable(backward compatibile), 1 - Enable)
+                                // this is basically for VSS use since VSS needs to support 96 channels, and
+                                // there is originally 5 bits only for channel number in the header.
+                                // With these two extra bits, the channel number becomes ((Channel_Ext<<5)|Channel).
+    unsigned int Channel_Ext : 2;
+    unsigned int StreamType : 2; // 0-NormalStream, 1-VStream, 2-DualStream
+    unsigned int QI : 4;         // 4 bits : QI (0~16)
+
+    unsigned int Size; // [4]
+    unsigned int Time; // [4]
+
+    unsigned int NTSC_PAL : 1; // 1 bit : 0:NTSC/1:PAL
+    unsigned int ImgMode : 1;  // 1 bit : 0:Live/1:Playback
+    unsigned int Audio : 1;    // 1 bit : 0:Video/1:Audio
+    unsigned int DST : 1;      // 1 bit : DST
+    unsigned int Covert : 1;   // 1 bit : Covert
+    unsigned int Vloss : 1;    // 1 bit : Video loss
+    unsigned int AlarmIn : 1;  // 1 bit : Alarm In
+    unsigned int Motion : 1;   // 1 bit : Motion
+
+    unsigned int ExtraEnable : 1; // 1 bit  : 0: no extra         1: have extra
+    unsigned int EventEnable : 1; // 1 bit  : 0: Normal status    1: Event duration
+    unsigned int PPS : 6;         // 6 bits : Per-channel PPS Idx (0~127 level)
+
+    unsigned int Type : 3;    // 3 bits : type (0~7) 0: none 1: I-pic, 2: P-Pic, 3: B-Pic
+    unsigned int Channel : 5; // 5 bits : Channel No (0~31)
+    unsigned int Chksum : 8;  // [1]
+
+} DynacolorBasicIdx;
+
+// Extra Idx: 16 bytes
+
+typedef struct
+{
+    unsigned int DST_Minutes : 8; // 0~7 = 0 ~ 120 minutes
+    unsigned int IsDST_S_W : 1;   //   0 = summer time , 1 =winter time
+    unsigned int OverSpeed : 1;
+    unsigned int SkipPicCnt : 5;
+
+    // use one bit to represent exception alarm
+    // can't get exactually exception no here
+    unsigned int Exception : 1;
+    unsigned int SuperExtraSize : 16;
+
+    unsigned int Serno; // [4]
+
+    // Original tEventInfo16CH was broken 'cause of the byte alignment problem
+    // - use the following directly
+    // the first bit can descript first channel's evnet status, so that it can totally script 16 channels' status.
+    // if IP camera, the first bit also descripts the first IP cmaera's status.
+    char AlmIn[2];  // 16 channel, if Source of DynacolorBasicIdx = 0, it means analog camera's status. If Source = 1, it means IP camera's.
+    char Vloss[2];  // 16 channel, if Source of DynacolorBasicIdx = 0, it means analog camera's status. If Source = 1, it means IP camera's.
+    char Motion[2]; // 16 channel, if Source of DynacolorBasicIdx = 0, it means analog camera's status. If Source = 1, it means IP camera's.
+
+    unsigned char IsDVRRec : 2;
+
+    // For TimeZone setting
+    // - 0 means OFF (backward compatibility)
+    // - Delta : 30 min
+    // - Start from : -12:00
+    // - Aka.
+    //    1 : -12:00 (-720 min)
+    //    2 : -11:30 (-690 min)
+    //    3 : -11:00 (-660 min)
+    //    ....
+    //   25 : +00:00 (+000 min)
+    //    ....
+    //   41 : +08:00 (+480 min)
+    //   42 : +08:30 (+510 min)
+    //   43 : +09:00 (+540 min)
+    //    ....
+    //   51 : +13:00 (+780 min)
+
+    unsigned char TimeZone : 6;
+    char Chksum;
+
+} DynacolorExtraIdx;
+
+// Super Extra Index :
+//  type = 0
+//  remain_size = 108
+// structure to store cam title & extra data(GPS/Text)
+
+typedef struct
+{
+
+    // the type for DynacolorExtraIdx is fixed to 0
+    int type;
+
+    // the remain_size for DynacolorExtraIdx is fixed to : 12 + 96 = 108
+    int remain_size;
+
+    // CAM_TIT_LEN
+    char title[12];
+
+    //   Merge original account0 ~ account3
+    // - GPS & Text support will use the same place
+    // - REC_INDEX_EXTRA_TYPE, REC_INDEX_EXTRA_CH, REC_INDEX_EXTRA_LENGTH are
+    //   used for some specific info
+    // - refer to list.h for detail
+
+    char extra_data[96];
+
+} DynacolorSuperExtraIdx;
+
+typedef struct
+{
+    DynacolorBasicIdx Basic;
+    DynacolorExtraIdx Extra;
+    DynacolorSuperExtraIdx SuperExtra;
+} DynacolorHeader;
+
+typedef struct
+{
+    // 4 bytes
+    unsigned int start_code0 : 8; // must be 0x00
+    unsigned int start_code1 : 8; // must be 0x00
+    unsigned int start_code2 : 8; // must be 0x01
+    unsigned int format_id : 4;   // JPEG:0xd, MPEG4:0xe, H.264:0xf, Audio:0xc
+    unsigned int channel_id : 4;  // channel id from 0 to 15 for CH1 to CH16
+
+    unsigned int unused_0;
+    unsigned int unused_1;
+    unsigned int unused_2;
+    unsigned int unused_3;
+    unsigned int unused_4;
+
+    // size of the video body and this PES header (total 3 bytes including the markers)
+    unsigned int size_bit7to0 : 8;   // from bit7 to bit0
+    unsigned int size_bit10to8 : 3;  // from bit10 to bit8
+    unsigned int size_bit14to11 : 4; // from bit14 to bit11
+    unsigned int size_bit21to15 : 7; // from bit21 to bit15
+    unsigned int size_marker0 : 1;   // must be 0x1
+    unsigned int size_marker1 : 1;   // must be 0x1
+
+    // 1 byte for the picture type
+    unsigned int picture_type : 8;   // 1: I-slice, 2: P-slice, 3: B-slice
+    unsigned int is_interleaved : 1; // 0: even/odd fields are separated horizontally
+                                     // 1: even/odd fields are interleaved
+    unsigned int field_id : 2;       // 0: odd field, 1: even field, 2/3: undefined
+    unsigned int unused_5 : 29;
+
+} DynacolorPesHeader;
+
+typedef struct {
+    DynacolorHeader header;
+    DynacolorPesHeader pes_header;
+} DynacolorContext;
+
+int ff_dyna_read_packet_header(AVFormatContext *ctx, AVIOContext *pb, unsigned char *pes_data, DynacolorPesHeader *pes, unsigned int *size,
+                               time_t *time, DynacolorHeader *cdata_B, unsigned int *basicIdx_H, unsigned int *basicIdx_L,
+                               unsigned char first);
+int ff_dyna_get_stream_format(AVFormatContext *ctx, DynacolorHeader *header);
+int ff_dyna_build_pes_header(AVFormatContext *ctx, uint8_t *pes_data);
+int ff_dyna_check_pes_packet_header(AVFormatContext *ctx, int format_prefix);
+
+#endif
diff --git a/libavformat/version.h b/libavformat/version.h
index 18c2f5fec2..493a0b337f 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,7 +32,7 @@
 // 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  42
+#define LIBAVFORMAT_VERSION_MINOR  43
 #define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
-- 
2.17.1



More information about the ffmpeg-devel mailing list