diff mbox series

[FFmpeg-devel,v2,4/6] avformat: add argo_asf muxer

Message ID 20200804084552.1974751-5-zane@zanevaniperen.com
State Superseded
Headers show
Series add adpcm_argo encoder and argo_asf muxer
Related show

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate fail Make fate failed

Commit Message

Zane van Iperen Aug. 4, 2020, 8:46 a.m. UTC
Signed-off-by: Zane van Iperen <zane@zanevaniperen.com>
---
 Changelog                |   1 +
 libavformat/Makefile     |   1 +
 libavformat/allformats.c |   1 +
 libavformat/argo_asf.c   | 124 ++++++++++++++++++++++++++++++++++++++-
 libavformat/version.h    |   2 +-
 5 files changed, 127 insertions(+), 2 deletions(-)

Comments

Zane van Iperen Aug. 4, 2020, 9:27 a.m. UTC | #1
On Tue, 04 Aug 2020 08:46:41 +0000
"Zane van Iperen" <zane@zanevaniperen.com> wrote:

Disregard, this breaks FATE. Will post a follow-up later.
Zane van Iperen Aug. 4, 2020, 10 a.m. UTC | #2
On Tue, 04 Aug 2020 09:27:35 +0000
"Zane van Iperen" <zane@zanevaniperen.com> wrote:

> 
> On Tue, 04 Aug 2020 08:46:41 +0000
> "Zane van Iperen" <zane@zanevaniperen.com> wrote:
> 
> Disregard, this breaks FATE. Will post a follow-up later.
> 
Right, so there's two ways I can fix this, which would be the preferred
option?

1. Explicitly tell FATE to use ASF:

    diff --git a/tests/fate/lavf-container.mak b/tests/fate/lavf-container.mak
    index 9e0eed4851..87dda63579 100644
    --- a/tests/fate/lavf-container.mak
    +++ b/tests/fate/lavf-container.mak
    @@ -24,7 +24,7 @@ $(FATE_LAVF_CONTAINER): CMD = lavf_container
     $(FATE_LAVF_CONTAINER): REF = $(SRC_PATH)/tests/ref/lavf/$(@:fate-lavf-%=%)
     $(FATE_LAVF_CONTAINER): $(AREF) $(VREF)
     
    -fate-lavf-asf: CMD = lavf_container "" "-c:a mp2 -ar 44100" "-r 25"
    +fate-lavf-asf: CMD = lavf_container "" "-f asf -c:a mp2 -ar 44100" "-r 25"
     fate-lavf-avi fate-lavf-nut: CMD = lavf_container "" "-c:a mp2 -ar 44100 -threads 1"
     fate-lavf-dv:  CMD = lavf_container "-ar 48000 -channel_layout stereo" "-r 25 -s pal"
     fate-lavf-dv_pal:  CMD = lavf_container_timecode_nodrop "-ar 48000 -r 25 -s pal -ac 2 -f dv"

2. NULL'ify the extensions field of ff_argo_asf_muxer. Would require the user to
   specify "-f argo_asf" on the command line. This seems the nicer solution.

    diff --git a/libavformat/argo_asf.c b/libavformat/argo_asf.c
    index 6239d8eebb..01f8fc4dc7 100644
    --- a/libavformat/argo_asf.c
    +++ b/libavformat/argo_asf.c
    @@ -367,7 +367,10 @@ static int argo_asf_write_trailer(AVFormatContext *s)
     AVOutputFormat ff_argo_asf_muxer = {
         .name           = "argo_asf",
         .long_name      = NULL_IF_CONFIG_SMALL("Argonaut Games ASF"),
    -    .extensions     = "asf",
    +    /*
    +     * Can't have this as it conflicts with the actual ASF format.
    +     * .extensions     = "asf",
    +     */
         .audio_codec    = AV_CODEC_ID_ADPCM_ARGO,
         .video_codec    = AV_CODEC_ID_NONE,
         .init           = argo_asf_write_init,
    

Zane
diff mbox series

Patch

diff --git a/Changelog b/Changelog
index 0f0fbf2abb..0108f8f1a8 100644
--- a/Changelog
+++ b/Changelog
@@ -12,6 +12,7 @@  version <next>:
 - AV1 encoding support SVT-AV1
 - Cineform HD encoder
 - ADPCM Argonaut Games encoder
+- Argonaut Games ASF muxer
 
 
 version 4.3:
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 62d8cbb54e..610d43ca99 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -103,6 +103,7 @@  OBJS-$(CONFIG_APTX_HD_DEMUXER)           += aptxdec.o rawdec.o
 OBJS-$(CONFIG_APTX_HD_MUXER)             += rawenc.o
 OBJS-$(CONFIG_AQTITLE_DEMUXER)           += aqtitledec.o subtitles.o
 OBJS-$(CONFIG_ARGO_ASF_DEMUXER)          += argo_asf.o
+OBJS-$(CONFIG_ARGO_ASF_MUXER)            += argo_asf.o
 OBJS-$(CONFIG_ASF_DEMUXER)               += asfdec_f.o asf.o asfcrypt.o \
                                             avlanguage.o
 OBJS-$(CONFIG_ASF_O_DEMUXER)             += asfdec_o.o asf.o asfcrypt.o \
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index fd9e46e233..b7e59ae170 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -64,6 +64,7 @@  extern AVInputFormat  ff_aptx_hd_demuxer;
 extern AVOutputFormat ff_aptx_hd_muxer;
 extern AVInputFormat  ff_aqtitle_demuxer;
 extern AVInputFormat  ff_argo_asf_demuxer;
+extern AVOutputFormat ff_argo_asf_muxer;
 extern AVInputFormat  ff_asf_demuxer;
 extern AVOutputFormat ff_asf_muxer;
 extern AVInputFormat  ff_asf_o_demuxer;
diff --git a/libavformat/argo_asf.c b/libavformat/argo_asf.c
index 9de64dfab4..6239d8eebb 100644
--- a/libavformat/argo_asf.c
+++ b/libavformat/argo_asf.c
@@ -1,5 +1,5 @@ 
 /*
- * Argonaut Games ASF demuxer
+ * Argonaut Games ASF (de)muxer
  *
  * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com)
  *
@@ -63,6 +63,7 @@  typedef struct ArgoASFDemuxContext {
     uint32_t            blocks_read;
 } ArgoASFDemuxContext;
 
+#if CONFIG_ARGO_ASF_DEMUXER
 static void argo_asf_parse_file_header(ArgoASFFileHeader *hdr, const uint8_t *buf)
 {
     hdr->magic          = AV_RL32(buf + 0);
@@ -254,3 +255,124 @@  AVInputFormat ff_argo_asf_demuxer = {
     .read_header    = argo_asf_read_header,
     .read_packet    = argo_asf_read_packet
 };
+#endif
+
+#if CONFIG_ARGO_ASF_MUXER
+static int argo_asf_write_init(AVFormatContext *s)
+{
+    AVCodecParameters *par;
+
+    if (s->nb_streams != 1) {
+        av_log(s, AV_LOG_ERROR, "ASF files have exactly one stream\n");
+        return AVERROR(EINVAL);
+    }
+
+    par = s->streams[0]->codecpar;
+
+    if (par->codec_id != AV_CODEC_ID_ADPCM_ARGO) {
+        av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
+               avcodec_get_name(par->codec_id));
+        return AVERROR(EINVAL);
+    }
+
+    if (par->channels > 2) {
+        av_log(s, AV_LOG_ERROR, "ASF files only support up to 2 channels\n");
+        return AVERROR(EINVAL);
+    }
+
+    if (par->sample_rate > UINT16_MAX) {
+        av_log(s, AV_LOG_ERROR, "Sample rate too large\n");
+        return AVERROR(EINVAL);
+    }
+
+    if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) {
+        av_log(s, AV_LOG_ERROR, "Stream not seekable, unable to write output file\n");
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
+static void argo_asf_write_file_header(const ArgoASFFileHeader *fhdr, AVIOContext *pb)
+{
+    avio_wl32( pb, fhdr->magic);
+    avio_wl16( pb, fhdr->version_major);
+    avio_wl16( pb, fhdr->version_minor);
+    avio_wl32( pb, fhdr->num_chunks);
+    avio_wl32( pb, fhdr->chunk_offset);
+    avio_write(pb, fhdr->name, sizeof(fhdr->name));
+}
+
+static void argo_asf_write_chunk_header(const ArgoASFChunkHeader *ckhdr, AVIOContext *pb)
+{
+    avio_wl32(pb, ckhdr->num_blocks);
+    avio_wl32(pb, ckhdr->num_samples);
+    avio_wl32(pb, ckhdr->unk1);
+    avio_wl16(pb, ckhdr->sample_rate);
+    avio_wl16(pb, ckhdr->unk2);
+    avio_wl32(pb, ckhdr->flags);
+}
+
+static int argo_asf_write_header(AVFormatContext *s)
+{
+    AVCodecParameters  *par = s->streams[0]->codecpar;
+    ArgoASFFileHeader  fhdr;
+    ArgoASFChunkHeader chdr;
+
+    fhdr.magic         = ASF_TAG;
+    fhdr.version_major = 2;
+    fhdr.version_minor = 1;
+    fhdr.num_chunks    = 1;
+    fhdr.chunk_offset  = ASF_FILE_HEADER_SIZE;
+    strncpy(fhdr.name, av_basename(s->url), FF_ARRAY_ELEMS(fhdr.name));
+
+    chdr.num_blocks    = 0;
+    chdr.num_samples   = ASF_SAMPLE_COUNT;
+    chdr.unk1          = 0;
+    chdr.sample_rate   = par->sample_rate;
+    chdr.unk2          = ~0;
+    chdr.flags         = ASF_CF_BITS_PER_SAMPLE | ASF_CF_ALWAYS1;
+
+    if (par->channels == 2)
+        chdr.flags |= ASF_CF_STEREO;
+
+    argo_asf_write_file_header(&fhdr, s->pb);
+    argo_asf_write_chunk_header(&chdr, s->pb);
+    return 0;
+}
+
+static int argo_asf_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    if (pkt->size != 17 * s->streams[0]->codecpar->channels)
+        return AVERROR_INVALIDDATA;
+
+    if (s->streams[0]->nb_frames >= UINT32_MAX)
+        return AVERROR_INVALIDDATA;
+
+    avio_write(s->pb, pkt->data, pkt->size);
+    return 0;
+}
+
+static int argo_asf_write_trailer(AVFormatContext *s)
+{
+    int16_t ret;
+
+    if ((ret = avio_seek(s->pb, ASF_FILE_HEADER_SIZE, SEEK_SET) < 0))
+        return ret;
+
+    avio_wl32(s->pb, (uint32_t)s->streams[0]->nb_frames);
+    return 0;
+}
+
+AVOutputFormat ff_argo_asf_muxer = {
+    .name           = "argo_asf",
+    .long_name      = NULL_IF_CONFIG_SMALL("Argonaut Games ASF"),
+    .extensions     = "asf",
+    .audio_codec    = AV_CODEC_ID_ADPCM_ARGO,
+    .video_codec    = AV_CODEC_ID_NONE,
+    .init           = argo_asf_write_init,
+    .write_header   = argo_asf_write_header,
+    .write_packet   = argo_asf_write_packet,
+    .write_trailer  = argo_asf_write_trailer
+};
+#endif
\ No newline at end of file
diff --git a/libavformat/version.h b/libavformat/version.h
index 33cebed85e..4d31e1ec3e 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  49
+#define LIBAVFORMAT_VERSION_MINOR  50
 #define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \