From 5e50b1489a45207890580e801d216a5abce06344 Mon Sep 17 00:00:00 2001
From: Carl Eugen Hoyos <ceffmpeg@gmail.com>
Date: Fri, 18 Aug 2017 20:57:54 +0200
Subject: [PATCH] lavc/g726: Add a little-endian G.726 encoder.

Fixes ticket #6596.
---
 libavcodec/Makefile    |    1 +
 libavcodec/allcodecs.c |    2 +-
 libavcodec/g726.c      |   54 ++++++++++++++++++++++++++++++++++++++++--------
 libavcodec/put_bits.h  |   40 +++++++++++++++++++++++++++++++++++
 libavcodec/version.h   |    2 +-
 5 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index b0c39ac..982d7f5 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -763,6 +763,7 @@ OBJS-$(CONFIG_ADPCM_G722_ENCODER)         += g722.o g722dsp.o g722enc.o
 OBJS-$(CONFIG_ADPCM_G726_DECODER)         += g726.o
 OBJS-$(CONFIG_ADPCM_G726_ENCODER)         += g726.o
 OBJS-$(CONFIG_ADPCM_G726LE_DECODER)       += g726.o
+OBJS-$(CONFIG_ADPCM_G726LE_ENCODER)       += g726.o
 OBJS-$(CONFIG_ADPCM_IMA_AMV_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_APC_DECODER)      += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_IMA_DAT4_DECODER)     += adpcm.o adpcm_data.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 4712592..1e5942d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -549,7 +549,7 @@ static void register_all(void)
     REGISTER_DECODER(ADPCM_EA_XAS,      adpcm_ea_xas);
     REGISTER_ENCDEC (ADPCM_G722,        adpcm_g722);
     REGISTER_ENCDEC (ADPCM_G726,        adpcm_g726);
-    REGISTER_DECODER(ADPCM_G726LE,      adpcm_g726le);
+    REGISTER_ENCDEC (ADPCM_G726LE,      adpcm_g726le);
     REGISTER_DECODER(ADPCM_IMA_AMV,     adpcm_ima_amv);
     REGISTER_DECODER(ADPCM_IMA_APC,     adpcm_ima_apc);
     REGISTER_DECODER(ADPCM_IMA_DAT4,    adpcm_ima_dat4);
diff --git a/libavcodec/g726.c b/libavcodec/g726.c
index 6922b40..80cb064 100644
--- a/libavcodec/g726.c
+++ b/libavcodec/g726.c
@@ -292,7 +292,7 @@ static av_cold int g726_reset(G726Context *c)
     return 0;
 }
 
-#if CONFIG_ADPCM_G726_ENCODER
+#if CONFIG_ADPCM_G726_ENCODER || CONFIG_ADPCM_G726LE_ENCODER
 static int16_t g726_encode(G726Context* c, int16_t sig)
 {
     uint8_t i;
@@ -308,6 +308,8 @@ static av_cold int g726_encode_init(AVCodecContext *avctx)
 {
     G726Context* c = avctx->priv_data;
 
+    c->little_endian = !strcmp(avctx->codec->name, "g726le");
+
     if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL &&
         avctx->sample_rate != 8000) {
         av_log(avctx, AV_LOG_ERROR, "Sample rates other than 8kHz are not "
@@ -356,9 +358,17 @@ static int g726_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
     init_put_bits(&pb, avpkt->data, avpkt->size);
 
     for (i = 0; i < frame->nb_samples; i++)
-        put_bits(&pb, c->code_size, g726_encode(c, *samples++));
-
-    flush_put_bits(&pb);
+        if (c->little_endian) {
+            put_bits_le(&pb, c->code_size, g726_encode(c, *samples++));
+        } else {
+            put_bits(&pb, c->code_size, g726_encode(c, *samples++));
+        }
+
+    if (c->little_endian) {
+        flush_put_bits_le(&pb);
+    } else {
+        flush_put_bits(&pb);
+    }
 
     avpkt->size = out_size;
     *got_packet_ptr = 1;
@@ -372,6 +382,13 @@ static const AVOption options[] = {
     { NULL },
 };
 
+static const AVCodecDefault defaults[] = {
+    { "b", "0" },
+    { NULL },
+};
+#endif
+
+#if CONFIG_ADPCM_G726_ENCODER
 static const AVClass g726_class = {
     .class_name = "g726",
     .item_name  = av_default_item_name,
@@ -379,11 +396,6 @@ static const AVClass g726_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
-static const AVCodecDefault defaults[] = {
-    { "b", "0" },
-    { NULL },
-};
-
 AVCodec ff_adpcm_g726_encoder = {
     .name           = "g726",
     .long_name      = NULL_IF_CONFIG_SMALL("G.726 ADPCM"),
@@ -400,6 +412,30 @@ AVCodec ff_adpcm_g726_encoder = {
 };
 #endif
 
+#if CONFIG_ADPCM_G726LE_ENCODER
+static const AVClass g726le_class = {
+    .class_name = "g726le",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_adpcm_g726le_encoder = {
+    .name           = "g726le",
+    .long_name      = NULL_IF_CONFIG_SMALL("G.726 little endian ADPCM (\"right-justified\")"),
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_ADPCM_G726LE,
+    .priv_data_size = sizeof(G726Context),
+    .init           = g726_encode_init,
+    .encode2        = g726_encode_frame,
+    .capabilities   = AV_CODEC_CAP_SMALL_LAST_FRAME,
+    .sample_fmts    = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
+                                                     AV_SAMPLE_FMT_NONE },
+    .priv_class     = &g726le_class,
+    .defaults       = defaults,
+};
+#endif
+
 #if CONFIG_ADPCM_G726_DECODER || CONFIG_ADPCM_G726LE_DECODER
 static av_cold int g726_decode_init(AVCodecContext *avctx)
 {
diff --git a/libavcodec/put_bits.h b/libavcodec/put_bits.h
index b85e88f..1ceb1cc 100644
--- a/libavcodec/put_bits.h
+++ b/libavcodec/put_bits.h
@@ -119,6 +119,18 @@ static inline void flush_put_bits(PutBitContext *s)
     s->bit_buf  = 0;
 }
 
+static inline void flush_put_bits_le(PutBitContext *s)
+{
+    while (s->bit_left < 32) {
+        av_assert0(s->buf_ptr < s->buf_end);
+        *s->buf_ptr++ = s->bit_buf;
+        s->bit_buf  >>= 8;
+        s->bit_left  += 8;
+    }
+    s->bit_left = 32;
+    s->bit_buf  = 0;
+}
+
 #ifdef BITSTREAM_WRITER_LE
 #define avpriv_align_put_bits align_put_bits_unsupported_here
 #define avpriv_put_string ff_put_string_unsupported_here
@@ -197,6 +209,34 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value)
     s->bit_left = bit_left;
 }
 
+static inline void put_bits_le(PutBitContext *s, int n, unsigned int value)
+{
+    unsigned int bit_buf;
+    int bit_left;
+
+    av_assert2(n <= 31 && value < (1U << n));
+
+    bit_buf  = s->bit_buf;
+    bit_left = s->bit_left;
+
+    bit_buf |= value << (32 - bit_left);
+    if (n >= bit_left) {
+        if (3 < s->buf_end - s->buf_ptr) {
+            AV_WL32(s->buf_ptr, bit_buf);
+            s->buf_ptr += 4;
+        } else {
+            av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n");
+            av_assert2(0);
+        }
+        bit_buf     = value >> bit_left;
+        bit_left   += 32;
+    }
+    bit_left -= n;
+
+    s->bit_buf  = bit_buf;
+    s->bit_left = bit_left;
+}
+
 static inline void put_sbits(PutBitContext *pb, int n, int32_t value)
 {
     av_assert2(n >= 0 && n <= 31);
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 02c4f41..7473000 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  57
-#define LIBAVCODEC_VERSION_MINOR 102
+#define LIBAVCODEC_VERSION_MINOR 103
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
-- 
1.7.10.4

