[Ffmpeg-devel] [PATCH] dumping support for encrypted MXFs
Reimar Döffinger
Reimar.Doeffinger
Wed Jan 10 20:18:09 CET 2007
Hello,
On Wed, Jan 10, 2007 at 01:45:55PM +0100, Baptiste Coudurier wrote:
> Reimar D?ffinger wrote:
> > attached patch would at least allow dumping of encrypted streams with
> > MPlayer's -dumpvideo/-dumpaudio.
> > This is not too useful and a bit hackish (since there is no indication
> > whether we have an encrypted stream or not), but on the other hand it
> > still seems like an improvement over the current treatment (mxf_read_header
> > parses the file until EOF).
> >
> > Greetings,
> > Reimar D?ffinger
> >
> > [...]
> >
> > @@ -1062,7 +1065,8 @@
> > seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den);
> > url_fseek(&s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET);
> > if (!mxf_read_sync(&s->pb, mxf_essence_element_key, 12))
> > - return -1;
> > + if (!mxf_read_sync(&s->pb, mxf_enc_essence_element_key, 12))
> > + return -1;
> >
> > /* found KLV key */
> > url_fseek(&s->pb, -12, SEEK_CUR);
> >
>
> That won't work since mxf_read_sync will always match essence element
> key since it is present within encrypted triplet, and mxf_read_sync will
> read until EOF is reached, so you need to seek back (yes that's a bit ugly).
Removed that part, seeking will not be implemented for now. Though a
possible quick hack would be to set a flag if the file contains an
encrypted track and then search for encrypted on seek.
> I would prefer to use mxf_encrypted_triplet_key like in specs, and it is
> a complete key (16 bytes) according to specs.
Fixed.
> It seems to work because there is an hack when mxf only contains one
> track, what if multiple streams are encrypted ?
> You need to parse further into the encrypted triplet to get track number .
Hopefully fixed, too (though I don't have files to test).
I added a GET_BER macro, to libavutil right now, but probably it does
not make sense to put it there right now. Any comments on that? Should I
put that macro "back" in mxf.c?
There is also a possible performance decrease with my changes, packets
for which we can not find a track index are not url_fskip'd but instead
read and the AVPacket then freed again.
Greetings,
Reimar D?ffinger
-------------- next part --------------
Index: libavformat/mxf.c
===================================================================
--- libavformat/mxf.c (revision 7422)
+++ libavformat/mxf.c (working copy)
@@ -173,6 +173,7 @@
/* partial keys to match */
static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 };
static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 };
+static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 };
#define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
@@ -181,20 +182,8 @@
static int64_t klv_decode_ber_length(ByteIOContext *pb)
{
- int64_t size = 0;
- uint8_t length = get_byte(pb);
- int type = length >> 7;
-
- if (type) { /* long form */
- int bytes_num = length & 0x7f;
- /* SMPTE 379M 5.3.4 guarantee that bytes_num must not exceed 8 bytes */
- if (bytes_num > 8)
- return -1;
- while (bytes_num--)
- size = size << 8 | get_byte(pb);
- } else {
- size = length & 0x7f;
- }
+ uint64_t size;
+ GET_BER(size, get_byte(pb), return -1;);
return size;
}
@@ -210,6 +199,8 @@
{
int i;
+ if (!IS_KLV_KEY(klv->key, mxf_essence_element_key))
+ return -1;
for (i = 0; i < s->nb_streams; i++) {
MXFTrack *track = s->streams[i]->priv_data;
/* SMPTE 379M 7.3 */
@@ -249,6 +240,28 @@
return 0;
}
+static int get_enc_src_klv(AVPacket *pkt, KLVPacket *klv) {
+ uint64_t size;
+ uint8_t *p = pkt->data;
+ uint8_t *end = &pkt->data[pkt->size];
+ // crypto context
+ if (&p[9] > end) return -1;
+ GET_BER(size, *p++ , return -1;);
+ if (size != 16) return -1;
+ p += size;
+ // plaintext offset
+ if (&p[9] > end) return -1;
+ GET_BER(size, *p++ , return -1;);
+ if (size != 8) return -1;
+ p += size;
+ // source klv key
+ if (&p[9 + 16] > end) return -1;
+ GET_BER(size, *p++ , return -1;);
+ if (size != 16) return -1;
+ memcpy(&klv->key, p, 16);
+ return 0;
+}
+
static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
KLVPacket klv;
@@ -261,13 +274,9 @@
#ifdef DEBUG
PRINT_KEY("read packet", klv.key);
#endif
- if (IS_KLV_KEY(klv.key, mxf_essence_element_key)) {
- int index = mxf_get_stream_index(s, &klv);
- if (index < 0) {
- av_log(s, AV_LOG_ERROR, "error getting stream index\n");
- url_fskip(&s->pb, klv.length);
- return -1;
- }
+ if (IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
+ IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) {
+ int index;
/* check for 8 channels AES3 element */
if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) {
if (mxf_get_d10_aes3_packet(&s->pb, s->streams[index], pkt, klv.length) < 0) {
@@ -276,6 +285,15 @@
}
} else
av_get_packet(&s->pb, pkt, klv.length);
+ if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) &&
+ get_enc_src_klv(pkt, &klv) < 0)
+ av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n");
+ index = mxf_get_stream_index(s, &klv);
+ if (index < 0) {
+ av_log(s, AV_LOG_ERROR, "error getting stream index\n");
+ av_free_packet(pkt);
+ return -1;
+ }
pkt->stream_index = index;
return 0;
} else
@@ -982,7 +1000,8 @@
#ifdef DEBUG
PRINT_KEY("read header", klv.key);
#endif
- if (IS_KLV_KEY(klv.key, mxf_essence_element_key)) {
+ if (IS_KLV_KEY(klv.key, mxf_essence_element_key) ||
+ IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) {
/* FIXME avoid seek */
url_fseek(&s->pb, klv.offset, SEEK_SET);
break;
Index: libavutil/common.h
===================================================================
--- libavutil/common.h (revision 7422)
+++ libavutil/common.h (working copy)
@@ -201,6 +201,30 @@
#define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24))
/*!
+ * \def GET_BER(val, GET_BYTE, ERROR)
+ * converts BER encoded integer (up to 8 bytes long) to its 64-bit value
+ * \param val is the output and should be of type uint64_t. It holds the converted
+ * 64 bit integer and should be a left value.
+ * \param GET_BYTE gets BER encoded bytes from any proper source. It can be
+ * a function or a statement whose return value or evaluated value is of type
+ * uint8_t. It will be executed up to 9 times.
+ * \param ERROR action that should be taken when an invalid BER byte is returned
+ * from GET_BYTE. It should be a statement that jumps out of the macro,
+ * like exit(), goto, return, break, or continue.
+ */
+#define GET_BER(val, GET_BYTE, ERROR)\
+ val= GET_BYTE;\
+ if (val & 0x80) { /* long form */\
+ int bytes_num = val & 0x7f;\
+ val = 0;\
+ /* SMPTE 379M 5.3.4 guarantee that bytes_num must not exceed 8 bytes */\
+ if (bytes_num > 8)\
+ ERROR\
+ while (bytes_num--)\
+ val = val << 8 | GET_BYTE;\
+ }
+
+/*!
* \def GET_UTF8(val, GET_BYTE, ERROR)
* converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form
* \param val is the output and should be of type uint32_t. It holds the converted
More information about the ffmpeg-devel
mailing list