hex_to_data should probably move to lavu before this is merged.
This is probably a good case for sub_charenc to run _after_ the decoder.
I could see an argument that this should go in the demuxer instead. Thoughts?
---
libavcodec/samidec.c | 78
1 file changed, 78 insertions(+)
diff --git a/libavcodec/samidec.c b/libavcodec/samidec.c
index 8dd2749..f279f8a 100644
--- a/libavcodec/samidec.c
+++ b/libavcodec/samidec.c
@@ -27,16 +27,53 @@
#include "ass.h"
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
+#include "libavutil/aes.h"
+#include "libavutil/opt.h"
+#include "libavformat/internal.h"
#include "htmlsubtitles.h"
typedef struct {
+AVClass *class;
AVBPrint source;
AVBPrint content;
AVBPrint encoded_source;
AVBPrint encoded_content;
AVBPrint full;
+uint8_t *key;
+int key_size;
+uint8_t *iv;
+int iv_size;
+struct AVAES *aes;
} SAMIContext;
+static int hex_to_data(uint8_t *data, const char *p)
+{
+int c, len, v;
+
+len = 0;
+v = 1;
+for (;;) {
+p += strspn(p, SPACE_CHARS);
+if (*p == '\0')
+break;
+c = av_toupper((unsigned char) *p++);
+if (c >= '0' && c <= '9')
+c = c - '0';
+else if (c >= 'A' && c <= 'F')
+c = c - 'A' + 10;
+else
+break;
+v = (v << 4) | c;
+if (v & 0x100) {
+if (data)
+data[len] = v;
+len++;
+v = 1;
+}
+}
+return len;
+}
+
static int sami_paragraph_to_ass(AVCodecContext *avctx, const char *src)
{
SAMIContext *sami = avctx->priv_data;
@@ -51,6 +88,18 @@ static int sami_paragraph_to_ass(AVCodecContext *avctx,
const char *src)
av_bprint_clear(>encoded_content);
av_bprint_clear(>content);
av_bprint_clear(>encoded_source);
+
+p = av_stristr(p, "", );
+if (sami->aes &&
+av_stristr(tag, "Encrypted=true") || av_stristr(tag,
"Encrypted=\"true\"")) {
+char iv[16];
+int len = hex_to_data(p, p);
+memcpy(iv, sami->iv, FFMIN(sizeof(iv), sami->iv_size));
+av_aes_crypt(sami->aes, p, p, len / 16, iv, 1);
+*(p + len) = 0;
+}
+
for (;;) {
char *saveptr = NULL;
int prev_chr_is_space = 0;
@@ -158,6 +207,18 @@ static av_cold int sami_init(AVCodecContext *avctx)
av_bprint_init(>encoded_source, 0, 2048);
av_bprint_init(>encoded_content, 0, 2048);
av_bprint_init(>full,0, 2048);
+
+if (sami->key && sami->iv && *sami->iv && !sami->iv_size)
+sami->iv_size = strlen(sami->iv);
+
+if (sami->key_size && sami->iv_size) {
+sami->aes = av_aes_alloc();
+if (!sami->aes)
+return ENOMEM;
+
+av_aes_init(sami->aes, sami->key, 256, 1);
+}
+
return ff_ass_subtitle_header_default(avctx);
}
@@ -172,6 +233,22 @@ static av_cold int sami_close(AVCodecContext *avctx)
return 0;
}
+#define OFFSET(x) offsetof(SAMIContext, x)
+#define FLAGS AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+{ "key", "Decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, { .str = NULL
}, 0, 0, FLAGS},
+{ "iv", "Decryption IV", OFFSET(iv), AV_OPT_TYPE_BINARY, { .str = NULL },
0, 0, FLAGS},
+{ "iv_str", "Decryption IV", OFFSET(iv), AV_OPT_TYPE_STRING, { .str = NULL
}, 0, 0, FLAGS},
+{ NULL },
+};
+
+static const AVClass sami_class = {
+.class_name = "sami",
+.item_name = av_default_item_name,
+.option = options,
+.version= LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_sami_decoder = {
.name = "sami",
.long_name = NULL_IF_CONFIG_SMALL("SAMI subtitle"),
@@ -181,4 +258,5 @@ AVCodec ff_sami_decoder = {
.init = sami_init,
.close = sami_close,
.decode = sami_decode_frame,
+.priv_class = _class,
};
--
2.6.0
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel