[FFmpeg-devel] [RFC][PATCH 3/3] tta: Add support for encrypted streams

James Almer jamrial at gmail.com
Mon Jan 28 08:32:54 CET 2013


The code to decrypt data is added to the decoder, and
the code needed to provide the decrypt key is added
to the TTA demuxer.

Any other container that supports TTA streams will
need extra code to process the password and send it
to the decoder using packet side data (main extradata
is used for the TTA header).

Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavcodec/tta.c  | 28 +++++++++++++++++++---------
 libavformat/tta.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/libavcodec/tta.c b/libavcodec/tta.c
index fb793be..9cad3a1 100644
--- a/libavcodec/tta.c
+++ b/libavcodec/tta.c
@@ -34,6 +34,7 @@
 #include "get_bits.h"
 #include "internal.h"
 #include "libavutil/crc.h"
+#include "libavutil/mem.h"
 
 #define FORMAT_SIMPLE    1
 #define FORMAT_ENCRYPTED 2
@@ -44,7 +45,7 @@ typedef struct TTAFilter {
     int32_t qm[MAX_ORDER];
     int32_t dx[MAX_ORDER];
     int32_t dl[MAX_ORDER];
-} TTAFilter;
+} DECLARE_ALIGNED(16, , TTAFilter);
 
 typedef struct TTARice {
     uint32_t k0, k1, sum0, sum1;
@@ -93,8 +94,13 @@ static const int32_t ttafilter_configs[4] = {
     12
 };
 
-static void ttafilter_init(TTAFilter *c, int32_t shift) {
+static void ttafilter_init(TTAFilter *c, int32_t shift, const uint8_t *pass) {
     memset(c, 0, sizeof(TTAFilter));
+    if (pass) {
+        int i;
+        for(i = 0; i < 8; i++)
+            c->qm[i] = sign_extend(pass[i], 8);
+    }
     c->shift = shift;
    c->round = shift_1[shift-1];
 //    c->round = 1 << (shift - 1);
@@ -200,10 +206,6 @@ static av_cold int tta_decode_init(AVCodecContext * avctx)
             av_log(avctx, AV_LOG_ERROR, "Invalid format\n");
             return AVERROR_INVALIDDATA;
         }
-        if (s->format == FORMAT_ENCRYPTED) {
-            av_log_missing_feature(avctx, "Encrypted TTA", 0);
-            return AVERROR_PATCHWELCOME;
-        }
         avctx->channels = s->channels = get_bits(&s->gb, 16);
         if (s->channels > 1 && s->channels < 9)
             avctx->channel_layout = tta_channel_layouts[s->channels-2];
@@ -293,8 +295,8 @@ static av_cold int tta_decode_init(AVCodecContext * avctx)
 static int tta_decode_frame(AVCodecContext *avctx, void *data,
                             int *got_frame_ptr, AVPacket *avpkt)
 {
-    const uint8_t *buf = avpkt->data;
-    int buf_size = avpkt->size;
+    const uint8_t *buf = avpkt->data, *sd_data = NULL;
+    int buf_size = avpkt->size, sd_size;
     TTAContext *s = avctx->priv_data;
     int i, ret;
     int cur_chan = 0, framelen = s->frame_length;
@@ -318,10 +320,18 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
     if (s->bps == 3)
         s->decode_buffer = (int32_t *)s->frame.data[0];
 
+    if (s->format == FORMAT_ENCRYPTED) {
+        sd_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &sd_size);
+        if (!sd_data || sd_size != 8) {
+            av_log(avctx, AV_LOG_ERROR, "Encrypted frame with no decryption info detected");
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
     // init per channel states
     for (i = 0; i < s->channels; i++) {
         s->ch_ctx[i].predictor = 0;
-        ttafilter_init(&s->ch_ctx[i].filter, ttafilter_configs[s->bps-1]);
+        ttafilter_init(&s->ch_ctx[i].filter, ttafilter_configs[s->bps-1], sd_data);
         rice_init(&s->ch_ctx[i].rice, 10, 10);
     }
 
diff --git a/libavformat/tta.c b/libavformat/tta.c
index 445389e..d824082 100644
--- a/libavformat/tta.c
+++ b/libavformat/tta.c
@@ -23,12 +23,22 @@
 #include "avformat.h"
 #include "internal.h"
 #include "id3v1.h"
+#include "libavutil/crc.h"
 #include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+
+#define FORMAT_SIMPLE    1
+#define FORMAT_ENCRYPTED 2
 
 typedef struct {
+    const AVClass *tta_demuxer_class;
     int totalframes, currentframe;
     int frame_size;
     int last_frame_size;
+    int format;
+    uint8_t crc_pass[8];
+    uint8_t *pass;
 } TTAContext;
 
 static int tta_probe(AVProbeData *p)
@@ -44,7 +54,7 @@ static int tta_read_header(AVFormatContext *s)
 {
     TTAContext *c = s->priv_data;
     AVStream *st;
-    int i, channels, bps, samplerate;
+    int i, channels, bps, samplerate, format;
     uint64_t framepos, start_offset;
     uint32_t datalen;
 
@@ -55,7 +65,22 @@ static int tta_read_header(AVFormatContext *s)
     if (avio_rl32(s->pb) != AV_RL32("TTA1"))
         return -1; // not tta file
 
-    avio_skip(s->pb, 2); // FIXME: flags
+    format = avio_rl16(s->pb);
+    if (format == FORMAT_ENCRYPTED) {
+        uint64_t crc;
+
+        if (!c->pass) {
+            av_log(s, AV_LOG_ERROR, "Missing password for encrypted stream. Please use the -password option\n");
+            return AVERROR(EINVAL);
+        }
+
+        crc = av_crc2(av_crc2_get_table(AV_CRC2_64_ECMA), -1, c->pass, strlen(c->pass)) ^ UINT64_MAX;
+        AV_WB64(c->crc_pass, crc);
+    } else if (format > 2){
+        av_log(s, AV_LOG_ERROR, "Invalid format\n");
+        return AVERROR_INVALIDDATA;
+    }
+
     channels = avio_rl16(s->pb);
     bps = avio_rl16(s->pb);
     samplerate = avio_rl32(s->pb);
@@ -78,6 +103,7 @@ static int tta_read_header(AVFormatContext *s)
         c->last_frame_size = c->frame_size;
     c->totalframes = datalen / c->frame_size + (c->last_frame_size < c->frame_size);
     c->currentframe = 0;
+    c->format = format;
 
     if(c->totalframes >= UINT_MAX/sizeof(uint32_t) || c->totalframes <= 0){
         av_log(s, AV_LOG_ERROR, "totalframes %d invalid\n", c->totalframes);
@@ -141,6 +167,14 @@ static int tta_read_packet(AVFormatContext *s, AVPacket *pkt)
     pkt->dts = st->index_entries[c->currentframe++].timestamp;
     pkt->duration = c->currentframe == c->totalframes ? c->last_frame_size :
                                                         c->frame_size;
+    if (c->format == FORMAT_ENCRYPTED) {
+        uint8_t *crc;
+
+        if ((crc = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, 8)) == NULL)
+            return AVERROR(ENOMEM);
+        memcpy(crc, c->crc_pass, 8);
+    }
+
     return ret;
 }
 
@@ -159,6 +193,20 @@ static int tta_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
     return 0;
 }
 
+#define OFFSET(x) offsetof(TTAContext, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+    { "password", "Set decoding password", OFFSET(pass), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, DEC },
+    { NULL },
+};
+
+static const AVClass tta_demuxer_class = {
+    .class_name = "TTA demuxer",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 AVInputFormat ff_tta_demuxer = {
     .name           = "tta",
     .long_name      = NULL_IF_CONFIG_SMALL("TTA (True Audio)"),
@@ -168,4 +216,5 @@ AVInputFormat ff_tta_demuxer = {
     .read_packet    = tta_read_packet,
     .read_seek      = tta_read_seek,
     .extensions     = "tta",
+    .priv_class     = &tta_demuxer_class,
 };
-- 
1.7.12.4



More information about the ffmpeg-devel mailing list