aboutsummaryrefslogtreecommitdiff
path: root/Src/h264/annexb.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/h264/annexb.c')
-rw-r--r--Src/h264/annexb.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/Src/h264/annexb.c b/Src/h264/annexb.c
new file mode 100644
index 00000000..cc6e10e0
--- /dev/null
+++ b/Src/h264/annexb.c
@@ -0,0 +1,224 @@
+#include "annexb.h"
+#include <bfc/platform/types.h>
+
+enum
+{
+ InitialUnit = 0,
+ NewUnit = 1, // start finding start code during AddData
+ MidUnit = 2, // need to find the next start code from next AddData call to form a complete unit
+ UnitReady = 3, // a new unit is ready and we are waiting for a GetUnit call
+};
+
+typedef struct annex_b_demuxer
+{
+ size_t buffer_position;
+ size_t number_of_zero_words; // number of zero words as identified from the first unit
+ size_t current_zero_words; // current zero word count, saved in case NALU crosses two AddData calls
+ int end_of_stream; // set to 1 when there's no more data (so we know not to look for the next start code)
+ int state;
+ size_t buffer_size;
+ uint8_t buffer[1]; // make sure this is last
+} AnnexBDemuxer;
+
+int AddData(const uint8_t **data, size_t *data_len); // data and length remaining are updated on exit. if data_len>0 on exit, call again after calling GetUnit
+void EndOfStream();
+
+
+h264_annexb_demuxer_t AnnexB_Create(int size)
+{
+ AnnexBDemuxer *demuxer = (AnnexBDemuxer *)malloc(sizeof(AnnexBDemuxer) + size);
+ demuxer->buffer_size = size; // MAX_CODED_FRAME_SIZE;
+ demuxer->state = InitialUnit;
+ demuxer->buffer_position = 0;
+ demuxer->number_of_zero_words = 0;
+ demuxer->current_zero_words = 0;
+ demuxer->end_of_stream = 0;
+ return (h264_annexb_demuxer_t)demuxer;
+}
+
+static int AnnexB_GetByte(const uint8_t **data, size_t *data_len, uint8_t *data_byte)
+{
+ if (*data_len)
+ {
+ *data_byte = **data;
+ *data = *data + 1;
+ *data_len = *data_len - 1;;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int AnnexB_AddData(h264_annexb_demuxer_t d, const void **_data, size_t *data_len)
+{
+ AnnexBDemuxer *demuxer = (AnnexBDemuxer *)d;
+ if (demuxer)
+ {
+ const uint8_t **data = (const uint8_t **)_data; // cast to something easier to do pointer math with
+ if (demuxer->state == InitialUnit)
+ {
+ // find start code with unknown number of initial zero bytes
+ while(demuxer->number_of_zero_words == 0)
+ {
+ uint8_t data_byte;
+ if (AnnexB_GetByte(data, data_len, &data_byte))
+ {
+ if (data_byte == 0)
+ {
+ demuxer->current_zero_words++;
+ }
+ else if (data_byte == 1 && demuxer->current_zero_words >= 2)
+ {
+ demuxer->number_of_zero_words = demuxer->current_zero_words;
+ demuxer->current_zero_words = 0;
+ demuxer->state = MidUnit;
+ }
+ else
+ {
+ // re-sync
+ demuxer->current_zero_words = 0;
+ }
+ }
+ else
+ {
+ return AnnexB_NeedMoreData;
+ }
+ }
+ }
+ else if (demuxer->state == NewUnit)
+ {
+ // find start code with known number of initial zero b ytes
+ while (demuxer->state == NewUnit)
+ {
+ uint8_t data_byte;
+ if (AnnexB_GetByte(data, data_len, &data_byte))
+ {
+ if (data_byte == 0)
+ {
+ demuxer->current_zero_words++;
+ }
+ else if (data_byte == 1 && demuxer->current_zero_words >= 2) // we might get more start words than required
+ {
+ demuxer->current_zero_words = 0;
+ demuxer->state = MidUnit;
+ }
+ else
+ {
+ // re-sync
+ demuxer->current_zero_words = 0;
+ }
+ }
+ else
+ {
+ return AnnexB_NeedMoreData;
+ }
+ }
+ }
+
+ if (demuxer->state == MidUnit) // no else because we fall through during the start code scanning)
+ {
+ uint8_t data_byte;
+ while (AnnexB_GetByte(data, data_len, &data_byte))
+ {
+ if (data_byte == 0)
+ {
+ demuxer->current_zero_words++; // might be the next start word
+ /* if (demuxer->current_zero_words == 3) // 00 00 00 is also a valid sequence for end-of-nal detection.
+ {
+ demuxer->state = UnitReady;
+ return AnnexB_UnitAvailable;
+ }*/
+ }
+ else if (data_byte == 1 && demuxer->current_zero_words >= 2)
+ {
+ while (demuxer->current_zero_words > demuxer->number_of_zero_words)
+ {
+ // write trailing zero bytes to stream
+ if (demuxer->buffer_position >= demuxer->buffer_size)
+ return AnnexB_BufferFull;
+ demuxer->buffer[demuxer->buffer_position++] = 0;
+ demuxer->current_zero_words--;
+ }
+ demuxer->current_zero_words = 0;
+ demuxer->state = UnitReady;
+ return AnnexB_UnitAvailable;
+ }
+ else
+ {
+ while (demuxer->current_zero_words)
+ {
+ // write any zero bytes that we read to the stream
+ if (demuxer->buffer_position >= demuxer->buffer_size)
+ return AnnexB_BufferFull;
+ demuxer->buffer[demuxer->buffer_position++] = 0;
+ demuxer->current_zero_words--;
+ }
+ if (demuxer->buffer_position >= demuxer->buffer_size)
+ return AnnexB_BufferFull;
+ demuxer->buffer[demuxer->buffer_position++] = data_byte;
+ }
+ }
+
+ if (demuxer->end_of_stream)
+ {
+ demuxer->state = UnitReady;
+ }
+ else
+ {
+ return AnnexB_NeedMoreData;
+ }
+ }
+
+ if (demuxer->state == UnitReady)
+ return AnnexB_UnitAvailable;
+
+ return AnnexB_NeedMoreData; // dunno how we'd get here
+ }
+ else
+ return AnnexB_Error;
+}
+
+void AnnexB_EndOfStream(h264_annexb_demuxer_t d)
+{
+ AnnexBDemuxer *demuxer = (AnnexBDemuxer *)d;
+ if (demuxer)
+ demuxer->end_of_stream = 1;
+}
+
+int AnnexB_GetUnit(h264_annexb_demuxer_t d, const void **data, size_t *data_len)
+{
+ AnnexBDemuxer *demuxer = (AnnexBDemuxer *)d;
+ if (demuxer)
+ {
+ if (demuxer->state == UnitReady)
+ {
+ *data = demuxer->buffer;
+ *data_len = demuxer->buffer_position;
+ demuxer->buffer_position = 0;
+
+ // if we've found the next start code, go to MidUnit state
+ if (demuxer->current_zero_words == 0)
+ {
+ demuxer->state = MidUnit;
+ }
+ else // no start code, need to find it
+ {
+ demuxer->state = NewUnit;
+ }
+ return AnnexB_UnitAvailable;
+ }
+ else
+ {
+ return AnnexB_NeedMoreData;
+ }
+ }
+
+ return AnnexB_Error;
+}
+
+void AnnexB_Destroy(h264_annexb_demuxer_t d)
+{
+ AnnexBDemuxer *demuxer = (AnnexBDemuxer *)d;
+ if (demuxer)
+ free(demuxer);
+} \ No newline at end of file