From d92cf5a6ad3a011b2a09ce62b166820f71d6ff41 Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Sun, 28 Oct 2012 12:06:09 +0100 Subject: [PATCH 09/16] Moved write_blocks from cli to libhimd * write_blocks is now called himd_writestream_writemp3 and is now placed in mdstream.c of libhimd. * Also moved the functions / structures it depended on and made the functions static. * himd_writestream_writemp3 now takes the mp3buffer instead of the mad stream, so the function prototype is still valid, if CONFIG_WITH_MAD is not set. * Some reformattig of himd_writestream_writemp3 (used mixed tab/spaces indentation. Only spaces now). --- himdcli/himdcli.c | 230 +--------------------------------------------------- libhimd/himd.h | 19 ++++- libhimd/mdstream.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+), 230 deletions(-) diff --git a/himdcli/himdcli.c b/himdcli/himdcli.c index a8eba15..9ceb2ec 100644 --- a/himdcli/himdcli.c +++ b/himdcli/himdcli.c @@ -335,241 +335,16 @@ void himd_dumpholes(struct himd * h) printf("%d: %05u-%05u\n", i, holes.holes[i].firstblock, holes.holes[i].lastblock); } -void block_init(struct blockinfo * b, short int nframes, short int lendata, unsigned int serial_number, unsigned char * cid) -{ - strncpy((char*)&b->type, "SMPA", 4); - b->nframes = nframes; - b->mcode = 3; - b->lendata = lendata; - b->reserved1 = 0; - b->serial_number = serial_number; - memset(&b->key, 0, 8); - // print_hex((unsigned char*)&b->key, 8); - memset(&b->iv, 0, 8); - memset(&b->backup_key, 0, 8); - b->backup_type = b->type; - memset(&b->reserved2, 0, 8); - b->backup_reserved = 0; - b->backup_mcode = b->mcode; - b->lo32_contentid = cid[16]*16777216+cid[17]*65536+cid[18]*256+cid[19]; - b->backup_serial_number = b->serial_number; -} - void block_printinfo(struct blockinfo * b) { printf("block %d, nframes: %d, lendata: %d\n", b->serial_number, b->nframes, b->lendata); } -struct abucket -{ - gint totsize; - gint nframes; - unsigned char *pbuf_current, *pbuf_end; - struct blockinfo block; -}; - -void bucket_init(struct abucket * pbucket) -{ - g_assert(pbucket != NULL); - memset(&pbucket->block, 0, sizeof(struct blockinfo)); - - pbucket->totsize = 0; - pbucket->nframes = 0; - pbucket->pbuf_current = &pbucket->block.audio_data[0]; - pbucket->pbuf_end = &pbucket->block.audio_data[HIMD_AUDIO_SIZE]; -} - -int bucket_append(struct abucket * pbucket, guchar * pframe, guint framelen) -{ - g_assert(pbucket != NULL); - g_assert(pframe != NULL); - - gint nbytes_to_add = framelen; - - // Buffer full? or too big frame for buffer? - if( (pbucket->totsize + nbytes_to_add) >= HIMD_AUDIO_SIZE) - { - if(pbucket->totsize == 0) - { - return 0; - } - return -1; - } - - g_assert(pbucket->pbuf_current <= pbucket->pbuf_end); - - memcpy(pbucket->pbuf_current, pframe, nbytes_to_add); - - pbucket->pbuf_current += nbytes_to_add; - pbucket->totsize += nbytes_to_add; - pbucket->nframes += 1; - - return nbytes_to_add; -} - -// -// Input parameters: -// -// A opened mp3-stream, himd-write-stream, duration structure, (TODO) block-obfuscation-key -// -// Return values: -// -// Return the number of written blocks and frames -// -// Side-effects: -// -// Writes audio blocks at the end of the ATDATA container file. Audio blocks contains all frames (TODO: ID3 frames) -// in a obfuscated form using a 4 byte key. -// - -#define HIMD_MP3_VAR_VERSION 0x40 -#define HIMD_MP3_VAR_LAYER 0x20 -#define HIMD_MP3_VAR_BITRATE 0x10 -#define HIMD_MP3_VAR_SRATE 0x08 -#define HIMD_MP3_VAR_CHMODE 0x04 -#define HIMD_MP3_VAR_PREEMPH 0x02 - -gint write_blocks(struct mad_stream *stream, struct himd_writestream *write_stream, mp3key key, - mad_timer_t *duration, gint *nblocks, gint *nframes, unsigned char * cid, - unsigned char *mp3codecinfo, struct himderrinfo * status) -{ - guchar var_flags = 0x80; - unsigned mpegvers = 3, mpeglayer = 1, mpegbitrate = 9, mpegsamprate = 0, - mpegchmode = 0, mpegpreemph = 0; - gboolean firsttime = TRUE; - struct abucket bucket; - struct mad_header header; - mad_timer_t mad_timer; - - gint iblock=0, iframe=0; - - mad_timer_reset(&mad_timer); - bucket_init(&bucket); - - while(1) { - - if(mad_header_decode(&header, stream) == -1) { - if(MAD_RECOVERABLE(stream->error)) - { - continue; - } - else { - break; - } - } - guchar * pframe = (gpointer) stream->this_frame; - gint framelen = (guint) (stream->next_frame - stream->this_frame); - /* "b" means "this Block" */ - unsigned bmpegvers, bmpeglayer, bmpegbitrate, bmpegsamprate, - bmpegchmode, bmpegpreemph; - - bmpegvers = (pframe[1] >> 3) & 0x03; - bmpeglayer = (pframe[1] >> 1) & 0x03; - bmpegbitrate = (pframe[2] >> 4) & 0x0F; - bmpegsamprate = (pframe[2] >> 2) & 0x03; - bmpegchmode = (pframe[3] >> 6) & 0x03; - bmpegpreemph = (pframe[3] >> 0) & 0x03; - - mad_timer_add(&mad_timer, header.duration); - - if(firsttime) { - bmpegvers = mpegvers; - bmpeglayer = mpeglayer; - bmpegbitrate = mpegbitrate; - bmpegsamprate = mpegsamprate; - bmpegchmode = mpegchmode; - bmpegpreemph = mpegpreemph; - firsttime = FALSE; - } else { - if(bmpegvers != mpegvers) { - var_flags |= HIMD_MP3_VAR_VERSION; - mpegvers = MIN(mpegvers, bmpegvers); /* smaller num -> higher version */ - } - if(bmpeglayer != mpeglayer) { - var_flags |= HIMD_MP3_VAR_LAYER; - mpeglayer = MIN(mpeglayer, bmpeglayer); /* smaller num -> higher layer */ - } - if(bmpegbitrate != mpegbitrate) { - /* TODO: check whether "free-form" streams need special handling */ - var_flags |= HIMD_MP3_VAR_BITRATE; - mpegbitrate = MAX(mpegbitrate, bmpegbitrate); - } - if(bmpegsamprate != mpegsamprate) { - var_flags |= HIMD_MP3_VAR_SRATE; - /* "1" is highest (48), "0" is medium (44), "2" is lowest (32) */ - if(mpegsamprate != 1) { - if(bmpegsamprate == 1) - mpegsamprate = bmpegsamprate; - else - mpegsamprate = MIN(mpegsamprate, bmpegsamprate); - } - } - if(bmpegchmode != mpegchmode) - /* TODO: find out how to choose "maximal" mode */ - var_flags |= HIMD_MP3_VAR_CHMODE; - if(bmpegpreemph != mpegpreemph) - /* TODO: find out how to choose "maximal" preemphasis */ - var_flags |= HIMD_MP3_VAR_PREEMPH; - } - - // Append frames to block - gint nbytes_added = bucket_append(&bucket, pframe, framelen); - if(nbytes_added < 0) { - block_init(&bucket.block, bucket.nframes, bucket.totsize, iblock, cid); - - // Encrypt block - unsigned i=0; - for(i=0;i < (bucket.totsize & ~7U); i++) - bucket.block.audio_data[i] ^= key[i & 3]; - - // Append block to ATDATA file - if(himd_writestream_write(write_stream, &bucket.block, status) < 0) - { - fprintf(stderr, "Failed to write block: %d", iblock); - perror("write block"); - } - - // remember number of frames in current audio block - iframe = bucket.nframes; - - bucket_init(&bucket); - - // Append the frame to a new block, that not would fit in the previous full block - nbytes_added = bucket_append(&bucket, pframe, framelen); - if(nbytes_added < 0) { - exit(1); - } - - iblock += 1; - continue; - } - else if(nbytes_added == 0) { - bucket_init(&bucket); - continue; - } - } - - if( (nblocks != NULL) && (nframes != NULL) && (duration != NULL)) - { - *nblocks = iblock; - *nframes = iframe; - duration->seconds = mad_timer.seconds; - } - - mp3codecinfo[0] = var_flags; - mp3codecinfo[1] = (mpegvers << 6) | (mpeglayer << 4) | (mpegbitrate); - mp3codecinfo[2] = (mpegsamprate << 6) | (mpegchmode << 4) | (mpegpreemph << 2); - - // close write-stream to atdata file - return iblock; -} - void himd_writemp3(struct himd *h, const char *filepath) { struct himderrinfo status; gint nblocks=0, nframes=0; - struct mad_stream stream; mad_timer_t duration; GMappedFile * mp3file; unsigned long mp3size; @@ -592,9 +367,6 @@ void himd_writemp3(struct himd *h, const char *filepath) mp3size = g_mapped_file_get_length(mp3file); mp3buffer = g_mapped_file_get_contents(mp3file); - mad_stream_init(&stream); - mad_stream_buffer(&stream, (unsigned char*)mp3buffer, mp3size); - // // Get track-key using track-index // @@ -622,7 +394,7 @@ void himd_writemp3(struct himd *h, const char *filepath) exit(1); } - write_blocks(&stream, &write_stream, key, &duration, &nblocks, &nframes, cid, mp3codecinfo, &status); + himd_writestream_writemp3(mp3buffer, mp3size, &write_stream, key, &duration, &nblocks, &nframes, cid, mp3codecinfo, &status); himd_writestream_close(&write_stream); // END: Write blocks to ATDATA diff --git a/libhimd/himd.h b/libhimd/himd.h index 8f7e203..a6f6b7a 100644 --- a/libhimd/himd.h +++ b/libhimd/himd.h @@ -31,6 +31,10 @@ #include #include "codecinfo.h" +#ifdef CONFIG_WITH_MAD +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -63,6 +67,13 @@ extern "C" { #define HIMD_AUDIO_SIZE 0x3FC0 #define HIMD_BLOCKINFO_SIZE 0x4000 +#define HIMD_MP3_VAR_VERSION 0x40 +#define HIMD_MP3_VAR_LAYER 0x20 +#define HIMD_MP3_VAR_BITRATE 0x10 +#define HIMD_MP3_VAR_SRATE 0x08 +#define HIMD_MP3_VAR_CHMODE 0x04 +#define HIMD_MP3_VAR_PREEMPH 0x02 + enum himdstatus { HIMD_OK, HIMD_STATUS_AUDIO_EOF, HIMD_ERROR_DISABLED_FEATURE, @@ -89,7 +100,8 @@ enum himdstatus { HIMD_OK, HIMD_ERROR_BAD_DATA_FORMAT, HIMD_ERROR_UNSUPPORTED_ENCRYPTION, HIMD_ERROR_ENCRYPTION_FAILURE, - HIMD_ERROR_OUT_OF_MEMORY }; + HIMD_ERROR_OUT_OF_MEMORY, + HIMD_ERROR_CANT_WRITE_BLOCK }; enum himd_rw_mode { HIMD_READ_ONLY, HIMD_READ_WRITE }; @@ -223,6 +235,11 @@ int himd_writestream_open(struct himd * himd, struct himd_writestream * stream, int himd_writestream_write(struct himd_writestream * stream, struct blockinfo *block, struct himderrinfo * status); void himd_writestream_close(struct himd_writestream * stream); +gint himd_writestream_writemp3(gchar *mp3buffer, unsigned long mp3size, struct himd_writestream *write_stream, + mp3key key, int *seconds, gint *nblocks, gint *nframes, unsigned char * cid, + unsigned char *mp3codecinfo, struct himderrinfo * status); + + struct himd_mp3stream { struct himd_blockstream stream; diff --git a/libhimd/mdstream.c b/libhimd/mdstream.c index 54a3837..083048e 100644 --- a/libhimd/mdstream.c +++ b/libhimd/mdstream.c @@ -487,8 +487,224 @@ int himd_mp3stream_read_frame(struct himd_mp3stream * stream, const unsigned cha return 0; } +/* himd_writestream_writemp3 and dependencies */ +static void block_init(struct blockinfo * b, short int nframes, short int lendata, unsigned int serial_number, unsigned char * cid) +{ + strncpy((char*)&b->type, "SMPA", 4); + b->nframes = nframes; + b->mcode = 3; + b->lendata = lendata; + b->reserved1 = 0; + b->serial_number = serial_number; + memset(&b->key, 0, 8); + // print_hex((unsigned char*)&b->key, 8); + memset(&b->iv, 0, 8); + memset(&b->backup_key, 0, 8); + b->backup_type = b->type; + memset(&b->reserved2, 0, 8); + b->backup_reserved = 0; + b->backup_mcode = b->mcode; + b->lo32_contentid = cid[16]*16777216+cid[17]*65536+cid[18]*256+cid[19]; + b->backup_serial_number = b->serial_number; +} + +struct abucket +{ + gint totsize; + gint nframes; + unsigned char *pbuf_current, *pbuf_end; + struct blockinfo block; +}; + +static void bucket_init(struct abucket * pbucket) +{ + g_assert(pbucket != NULL); + memset(&pbucket->block, 0, sizeof(struct blockinfo)); + + pbucket->totsize = 0; + pbucket->nframes = 0; + pbucket->pbuf_current = &pbucket->block.audio_data[0]; + pbucket->pbuf_end = &pbucket->block.audio_data[HIMD_AUDIO_SIZE]; +} + +static int bucket_append(struct abucket * pbucket, guchar * pframe, guint framelen) +{ + g_assert(pbucket != NULL); + g_assert(pframe != NULL); + + gint nbytes_to_add = framelen; + + // Buffer full? or too big frame for buffer? + if((pbucket->totsize + nbytes_to_add) >= HIMD_AUDIO_SIZE) + { + if(pbucket->totsize == 0) + return 0; + return -1; + } + + g_assert(pbucket->pbuf_current <= pbucket->pbuf_end); + + memcpy(pbucket->pbuf_current, pframe, nbytes_to_add); + + pbucket->pbuf_current += nbytes_to_add; + pbucket->totsize += nbytes_to_add; + pbucket->nframes += 1; + + return nbytes_to_add; +} + +// +// Input parameters: +// +// A buffer with mp3 data, the buffer size, himd-write-stream, seconds pointer, (TODO) block-obfuscation-key +// +// Return values: +// +// Return the number of written blocks and frames +// +// Side-effects: +// +// Writes audio blocks at the end of the ATDATA container file. Audio blocks contains all frames (TODO: ID3 frames) +// in a obfuscated form using a 4 byte key. +// +gint himd_writestream_writemp3(gchar *mp3buffer, unsigned long mp3size, struct himd_writestream *write_stream, + mp3key key, int *seconds, gint *nblocks, gint *nframes, unsigned char * cid, + unsigned char *mp3codecinfo, struct himderrinfo * status) +{ + guchar var_flags = 0x80; + unsigned mpegvers = 3, mpeglayer = 1, mpegbitrate = 9, mpegsamprate = 0, + mpegchmode = 0, mpegpreemph = 0; + gboolean firsttime = TRUE; + struct abucket bucket; + struct mad_header header; + struct mad_stream stream; + mad_timer_t mad_timer; + + gint iblock=0, iframe=0; + + mad_stream_init(&stream); + mad_stream_buffer(&stream, (unsigned char*)mp3buffer, mp3size); + + mad_timer_reset(&mad_timer); + bucket_init(&bucket); + + while(1) { + if(mad_header_decode(&header, &stream) == -1) { + if(MAD_RECOVERABLE(stream.error)) + continue; + else + break; + } + + guchar * pframe = (gpointer) stream.this_frame; + gint framelen = (guint) (stream.next_frame - stream.this_frame); + /* "b" means "this Block" */ + unsigned bmpegvers, bmpeglayer, bmpegbitrate, bmpegsamprate, + bmpegchmode, bmpegpreemph; + + bmpegvers = (pframe[1] >> 3) & 0x03; + bmpeglayer = (pframe[1] >> 1) & 0x03; + bmpegbitrate = (pframe[2] >> 4) & 0x0F; + bmpegsamprate = (pframe[2] >> 2) & 0x03; + bmpegchmode = (pframe[3] >> 6) & 0x03; + bmpegpreemph = (pframe[3] >> 0) & 0x03; + + mad_timer_add(&mad_timer, header.duration); + + if(firsttime) { + bmpegvers = mpegvers; + bmpeglayer = mpeglayer; + bmpegbitrate = mpegbitrate; + bmpegsamprate = mpegsamprate; + bmpegchmode = mpegchmode; + bmpegpreemph = mpegpreemph; + firsttime = FALSE; + } else { + if(bmpegvers != mpegvers) { + var_flags |= HIMD_MP3_VAR_VERSION; + mpegvers = MIN(mpegvers, bmpegvers); /* smaller num -> higher version */ + } + if(bmpeglayer != mpeglayer) { + var_flags |= HIMD_MP3_VAR_LAYER; + mpeglayer = MIN(mpeglayer, bmpeglayer); /* smaller num -> higher layer */ + } + if(bmpegbitrate != mpegbitrate) { + /* TODO: check whether "free-form" streams need special handling */ + var_flags |= HIMD_MP3_VAR_BITRATE; + mpegbitrate = MAX(mpegbitrate, bmpegbitrate); + } + if(bmpegsamprate != mpegsamprate) { + var_flags |= HIMD_MP3_VAR_SRATE; + /* "1" is highest (48), "0" is medium (44), "2" is lowest (32) */ + if(mpegsamprate != 1) { + if(bmpegsamprate == 1) + mpegsamprate = bmpegsamprate; + else + mpegsamprate = MIN(mpegsamprate, bmpegsamprate); + } + } + if(bmpegchmode != mpegchmode) + /* TODO: find out how to choose "maximal" mode */ + var_flags |= HIMD_MP3_VAR_CHMODE; + if(bmpegpreemph != mpegpreemph) + /* TODO: find out how to choose "maximal" preemphasis */ + var_flags |= HIMD_MP3_VAR_PREEMPH; + } + + // Append frames to block + gint nbytes_added = bucket_append(&bucket, pframe, framelen); + if(nbytes_added < 0) { + block_init(&bucket.block, bucket.nframes, bucket.totsize, iblock, cid); + + // Encrypt block + unsigned i=0; + for(i=0;i < (bucket.totsize & ~7U); i++) + bucket.block.audio_data[i] ^= key[i & 3]; + + // Append block to ATDATA file + if(himd_writestream_write(write_stream, &bucket.block, status) < 0) + { + set_status_printf(status, HIMD_ERROR_CANT_WRITE_BLOCK, _("Failed to write block: %d"), iblock); + perror("write block"); + } + + // remember number of frames in current audio block + iframe = bucket.nframes; + + bucket_init(&bucket); + + // Append the frame to a new block, that not would fit in the previous full block + nbytes_added = bucket_append(&bucket, pframe, framelen); + if(nbytes_added < 0) + exit(1); + + iblock += 1; + continue; + } + else if(nbytes_added == 0) { + bucket_init(&bucket); + continue; + } + } + + if((nblocks != NULL) && (nframes != NULL) && (seconds != NULL)) + { + *nblocks = iblock; + *nframes = iframe; + *seconds = mad_timer.seconds; + } + + mp3codecinfo[0] = var_flags; + mp3codecinfo[1] = (mpegvers << 6) | (mpeglayer << 4) | (mpegbitrate); + mp3codecinfo[2] = (mpegsamprate << 6) | (mpegchmode << 4) | (mpegpreemph << 2); + + // close write-stream to atdata file + return iblock; +} + #else + int himd_mp3stream_read_frame(struct himd_mp3stream * stream, const unsigned char ** frameout, unsigned int * lenout, struct himderrinfo * status) { (void)stream; @@ -499,6 +715,23 @@ int himd_mp3stream_read_frame(struct himd_mp3stream * stream, const unsigned cha return -1; } +gint himd_writestream_writemp3(gchar *mp3buffer, unsigned long mp3size, struct himd_writestream *write_stream, + mp3key key, int *seconds, gint *nblocks, gint *nframes, unsigned char * cid, + unsigned char *mp3codecinfo, struct himderrinfo * status) +{ + (void)mp3buffer; + (void)mp3size; + (void)write_stream; + (void)key; + (void)duration; + (void)nblocks; + (void)nframes; + (void)cid; + (void)mp3codecinfo; + set_status_const(status, HIMD_ERROR_DISABLED_FEATURE, _("Can't write mp3 data: Compiled without mad library")); + return -1; +} + #endif void himd_mp3stream_close(struct himd_mp3stream * stream) -- 1.8.0