From: David Flynn <[email protected]> Behavious is backwards compatible when pushing single aligned data units.
incorporates: - schroparse: remove useless tests, add guarantee comments Signed-off-by: David Flynn <[email protected]> --- schroedinger/schrodecoder.c | 20 +++++- schroedinger/schrodecoder.h | 5 ++ schroedinger/schroparse.c | 159 +++++++++++++++++++++++++++++++++++++++++++ schroedinger/schroparse.h | 11 +++ 4 files changed, 194 insertions(+), 1 deletions(-) diff --git a/schroedinger/schrodecoder.c b/schroedinger/schrodecoder.c index b3f4c83..a189c7d 100644 --- a/schroedinger/schrodecoder.c +++ b/schroedinger/schrodecoder.c @@ -114,6 +114,9 @@ schro_decoder_new (void) decoder->skip_value = 1.0; decoder->skip_ratio = 1.0; + decoder->input_buflist = schro_buflist_new (); + decoder->sps = schro_parse_sync_new (); + decoder->reference_queue = schro_queue_new (SCHRO_LIMIT_REFERENCE_FRAMES, (SchroQueueFreeFunc)schro_picture_unref); decoder->output_queue = schro_queue_new (SCHRO_LIMIT_REFERENCE_FRAMES, @@ -705,7 +708,7 @@ schro_decoder_set_flushing (SchroDecoder *decoder, int value) } int -schro_decoder_push (SchroDecoder *decoder, SchroBuffer *buffer) +schro_decoder_push_old (SchroDecoder *decoder, SchroBuffer *buffer) { SchroUnpack unpack; int parse_code; @@ -788,6 +791,21 @@ schro_decoder_push (SchroDecoder *decoder, SchroBuffer *buffer) } int +schro_decoder_push (SchroDecoder *decoder, SchroBuffer *buffer) +{ + /* 1. buffer is added to the decoder input queue. + * 2. The synchronizer extracts (if possible) a data unit for parsing */ + if (buffer) + schro_buflist_append (decoder->input_buflist, buffer); + + buffer = schro_parse_sync (decoder->sps, decoder->input_buflist); + if (!buffer) + return SCHRO_DECODER_OK; + + return schro_decoder_push_old (decoder, buffer); +} + +int schro_decoder_iterate_picture (SchroDecoder *decoder, SchroBuffer *buffer, SchroUnpack *unpack, int parse_code) { SchroPicture *picture; diff --git a/schroedinger/schrodecoder.h b/schroedinger/schrodecoder.h index 8e35214..3e0cdf3 100644 --- a/schroedinger/schrodecoder.h +++ b/schroedinger/schrodecoder.h @@ -11,6 +11,8 @@ #include <schroedinger/schroqueue.h> #include <schroedinger/schroasync.h> #include <schroedinger/schroarith.h> +#include <schroedinger/schrobufferlist.h> +#include <schroedinger/schroparse.h> SCHRO_BEGIN_DECLS @@ -42,6 +44,9 @@ struct _SchroDecoder { SchroOpenGL *opengl; int use_opengl; + SchroBufferList *input_buflist; + SchroParseSyncState *sps; + SchroPictureNumber next_frame_number; int major_version; diff --git a/schroedinger/schroparse.c b/schroedinger/schroparse.c index 36a4d35..1e80a21 100644 --- a/schroedinger/schroparse.c +++ b/schroedinger/schroparse.c @@ -176,3 +176,162 @@ schro_parse_decode_sequence_header (uint8_t *data, int length, return TRUE; } +typedef struct parse_info { + uint32_t next_parse_offset; + uint32_t prev_parse_offset; + uint_least8_t parse_code; +} parse_info_t; + +/* decode a parse info structure, storing the results in @*pi@ + * returns 0 if decoding is unsuccessful + * returns 1 on success */ +int +schro_parse_decode_parseinfo (uint8_t *data, unsigned length, parse_info_t *pi) +{ + if (length < 13) { + return 0; + } + + if (data[0] != 'B' || data[1] != 'B' || data[2] != 'C' || data[3] != 'D') { + return 0; + } + + pi->parse_code = data[4]; + pi->next_parse_offset = data[5] << 24 | data[6] << 16 | data[7] << 8 | data[8]; + pi->prev_parse_offset = data[9] << 24 | data[10] << 16 | data[11] << 8 | data[12]; + return 1; +} + +struct _SchroParseSyncState +{ + int sync_state; + unsigned offset; + uint32_t last_npo; +}; + +enum { + NOT_SYNCED = 0, + TRY_SYNC, + SYNCED, + SYNCED_INCOMPLETEDU, +}; + +SchroParseSyncState * +schro_parse_sync_new (void) +{ + return schro_malloc0 (sizeof(SchroParseSyncState)); +} + +void +schro_parse_sync_free (SchroParseSyncState *sps) +{ + schro_free (sps); +} + +SchroBuffer * +schro_parse_sync (SchroParseSyncState *sps, SchroBufferList *buflist) +{ + uint8_t tmp[13]; + const uint8_t *parse_code_prefix = (const uint8_t*)"BBCD"; + parse_info_t pu = {0}; + SchroBuffer *du; + + do { + switch (sps->sync_state) { + case NOT_SYNCED: { /* -> TRY_SYNC | NOT_SYNCED */ + /* find start code (offset), stop so as to include a whole PI */ + int found = schro_buflist_findbytes (buflist, &sps->offset, parse_code_prefix, 4); + /* xxx, worth flushing upto this point, although that is + * quite complicated. */ + if (!found) { + return NULL; + } + /* protect the case where there aren't 9 more bytes after end of + * parse_code_prefix: offset + 12 = last byte of parse_info */ + if (!schro_buflist_peekbytes (tmp, 1, buflist, sps->offset+12)) { + return NULL; + } + /* found, fall through */ + } + case TRY_SYNC: { /* -> SYNCED | NOT_SYNCED */ + parse_info_t pu1; + /* NB, we are guaranteed that reading 13 bytes from sps->offset will + * succeed, since NOT_SYNCED will not advance to this point if not */ + schro_buflist_peekbytes (tmp, 13, buflist, sps->offset); + if (!schro_parse_decode_parseinfo (tmp, 13, &pu1)) { + goto try_sync_fail; + } + /* Check that prev_parse_offset doesn't reference something not yet seen */ + if (sps->offset < pu1.prev_parse_offset) { + goto try_sync_fail; + } + /* NB, guaranteed that there are 13 bytes avaliable */ + schro_buflist_peekbytes (tmp, 13, buflist, sps->offset - pu1.prev_parse_offset); + if (!schro_parse_decode_parseinfo (tmp, 13, &pu)) { + goto try_sync_fail; + } + if (pu1.prev_parse_offset != pu.next_parse_offset) { +try_sync_fail: + sps->sync_state = NOT_SYNCED; + sps->offset++; + /* find somewhere else to try again */ + break; + } + sps->last_npo = pu.next_parse_offset; + /* offset was pointing at pu1, rewind to point at pu */ + sps->offset -= pu.next_parse_offset; + sps->sync_state = SYNCED; + break; + } + case SYNCED: { /* -> SYNCED | SYNCED_INCOMPLETEDU | NOT_SYNCED */ + int a; + if (schro_buflist_peekbytes (tmp, 13, buflist, sps->offset) < 13) + return NULL; + a = schro_parse_decode_parseinfo (tmp, 13, &pu); + if (!a || (sps->last_npo != pu.prev_parse_offset)) { + sps->sync_state = NOT_SYNCED; + break; + } + sps->last_npo = pu.next_parse_offset; + sps->sync_state = SYNCED; + break; + } + case SYNCED_INCOMPLETEDU: { /* -> SYNCED */ + /* NB, this is safe -- to get here we must've already read pu + * previously, so no need to check that it is ok again */ + schro_buflist_peekbytes (tmp, 13, buflist, sps->offset); + schro_parse_decode_parseinfo (tmp, 13, &pu); + sps->sync_state = SYNCED; + /* assume that the DU is complete this time */ + break; + } + } + } while (NOT_SYNCED == sps->sync_state); + + /* + * synced, attempt to extract a data unit + */ + + /* fixup for case where pu.next_parse_offset = 0 (eg, EOS) */ + if (!pu.next_parse_offset) { + pu.next_parse_offset = 13; + } + + /* flush everything upto the DU */ + schro_buflist_flush (buflist, sps->offset); + sps->offset = 0; + + /* try to extract the complete DU */ + du = schro_buflist_extract(buflist, 0, pu.next_parse_offset); + if (!du) { + /* the whole DU isn't in the buffer, try again */ + sps->sync_state = SYNCED_INCOMPLETEDU; + return NULL; + } + + /* flush everything upto the end of DU */ + schro_buflist_flush (buflist, pu.next_parse_offset); + + return du; +} + diff --git a/schroedinger/schroparse.h b/schroedinger/schroparse.h index 39a0e9a..e80e9c4 100644 --- a/schroedinger/schroparse.h +++ b/schroedinger/schroparse.h @@ -3,12 +3,23 @@ #define __SCHRO_PARSE_H__ #include <schroedinger/schrovideoformat.h> +#include <schroedinger/schrobufferlist.h> SCHRO_BEGIN_DECLS int schro_parse_decode_sequence_header (uint8_t *data, int length, SchroVideoFormat *video_format); +#ifdef SCHRO_ENABLE_UNSTABLE_API + +typedef struct _SchroParseSyncState SchroParseSyncState; + +SchroParseSyncState *schro_parse_sync_new (void); +void schro_parse_sync_free (SchroParseSyncState *); +SchroBuffer *schro_parse_sync (SchroParseSyncState *sps, SchroBufferList *input_bufer); + +#endif + SCHRO_END_DECLS #endif -- 1.5.6.5 ------------------------------------------------------------------------------ This SF.net email is sponsored by: SourcForge Community SourceForge wants to tell your story. http://p.sf.net/sfu/sf-spreadtheword _______________________________________________ Schrodinger-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/schrodinger-devel
