static bool input_context_FILE_read(input_context* ctx) { input_context_FILE* filectx = (input_context_FILE*)ctx; int free_space = ctx->input_buffer.capacity - ctx->input_buffer.size; int read_chunk_size; if (free_space < READ_CHUNK_SIZE) { int new_size = ctx->input_buffer.capacity + READ_CHUNK_SIZE; rbsp_buffer_resize(&ctx->input_buffer, new_size); read_chunk_size = ctx->input_buffer.capacity - ctx->input_buffer.size; } else { read_chunk_size = free_space; } int nread = fread(&ctx->input_buffer.data[ctx->input_buffer.size], 1,read_chunk_size, filectx->input_file); if (nread==0) { return false; } else { ctx->input_buffer.size += nread; return true; } }
LIBDE265_API de265_error de265_push_NAL(de265_decoder_context* de265ctx, const void* data8, int len, de265_PTS pts, void* user_data) { decoder_context* ctx = (decoder_context*)de265ctx; uint8_t* data = (uint8_t*)data8; // Cannot use byte-stream input and NAL input at the same time. assert(ctx->pending_input_NAL == NULL); NAL_unit* nal = alloc_NAL_unit(ctx, len, DE265_SKIPPED_BYTES_INITIAL_SIZE); rbsp_buffer_resize(&nal->nal_data, len); nal->nal_data.size = len; nal->pts = pts; nal->user_data = user_data; memcpy(nal->nal_data.data, data, len); remove_stuffing_bytes(nal); push_to_NAL_queue(ctx, nal); return DE265_OK; }
static de265_error process_data(decoder_context* ctx, const uint8_t* data, int len, int* out_nBytesProcessed) { *out_nBytesProcessed=0; /* printf("len=%d\n",len); for (int i=0;i<16;i++) { printf("%02x ",data[i]); } printf("\n"); */ // Resize output buffer so that complete input would fit. // We add 3, because in the worst case 3 extra bytes are created for an input byte. rbsp_buffer_resize(&ctx->nal_data, ctx->nal_data.size + len + 3); unsigned char* out = ctx->nal_data.data + ctx->nal_data.size; for (int i=0;i<len;i++) { (*out_nBytesProcessed)++; /* printf("state=%d input=%02x (%p) (output size: %d)\n",ctx->input_push_state, *data, data, out - ctx->nal_data.data); */ switch (ctx->input_push_state) { case 0: case 1: if (*data == 0) { ctx->input_push_state++; } else { return DE265_ERROR_NO_STARTCODE; } break; case 2: if (*data == 1) { ctx->input_push_state=3; ctx->num_skipped_bytes=0; } else if (*data == 0) { } // *out++ = 0; } else { return DE265_ERROR_NO_STARTCODE; } break; case 3: /* *out++ = 0; *out++ = 0; *out++ = 1; */ *out++ = *data; ctx->input_push_state = 4; break; case 4: *out++ = *data; ctx->input_push_state = 5; break; case 5: if (*data==0) { ctx->input_push_state=6; } else { *out++ = *data; } break; case 6: if (*data==0) { ctx->input_push_state=7; } else { *out++ = 0; *out++ = *data; ctx->input_push_state=5; } break; case 7: if (*data==0) { *out++ = 0; } else if (*data==3) { *out++ = 0; *out++ = 0; ctx->input_push_state=5; // remember which byte we removed int* skipped = (int *)malloc((ctx->num_skipped_bytes+1) * sizeof(int)); if (ctx->num_skipped_bytes>0) { memcpy(skipped, ctx->skipped_bytes, ctx->num_skipped_bytes * sizeof(int)); } if (ctx->skipped_bytes) { free(ctx->skipped_bytes); } skipped[ctx->num_skipped_bytes] = (out - ctx->nal_data.data) + ctx->num_skipped_bytes; ctx->skipped_bytes = skipped; ctx->num_skipped_bytes++; } else if (*data==1) { // decode this NAL ctx->nal_data.size = out - ctx->nal_data.data; de265_error err = de265_decode_NAL((de265_decoder_context*)ctx, &ctx->nal_data); // clear buffer for next NAL ctx->nal_data.size = 0; out = ctx->nal_data.data; ctx->input_push_state=3; ctx->num_skipped_bytes=0; if (err != DE265_OK) { data++; return err; } // when there are no free image buffers in the DPB, pause decoding if (!has_free_dpb_picture(ctx)) { data++; return err; } } else { *out++ = 0; *out++ = 0; *out++ = *data; ctx->input_push_state=5; } break; } data++; /* for (int i=0;i<out - ctx->nal_data.data;i++) { printf("%02x ",ctx->nal_data.data[i]); } printf("\n"); */ } if (*out_nBytesProcessed == len && ctx->end_of_stream && ctx->input_push_state != 8) { if (ctx->input_push_state<5) { return DE265_ERROR_EOF; } else if (ctx->input_push_state==6) { *out++ = 0; } else if (ctx->input_push_state==7) { *out++ = 0; *out++ = 0; } ctx->input_push_state=8; // end of stream, stop all processing // decode data ctx->nal_data.size = out - ctx->nal_data.data; de265_error err = de265_decode_NAL((de265_decoder_context*)ctx, &ctx->nal_data); if (err != DE265_OK) { return err; } push_current_picture_to_output_queue(ctx); // clear buffer ctx->nal_data.size = 0; out = ctx->nal_data.data; return DE265_OK; } ctx->nal_data.size = out - ctx->nal_data.data; return DE265_OK; }
void rbsp_buffer_append(rbsp_buffer* buffer, const unsigned char* data, int n) { rbsp_buffer_resize(buffer, buffer->size + n); memcpy(buffer->data + buffer->size, data, n); buffer->size += n; }
int read_nal_unit(input_context* ctx, rbsp_buffer* buffer) { buffer->size=0; // if there is not even a NAL header remaining in the input, we are at EOF if (ctx->input_buffer.size < 4+2) { bool more_data = ctx->refill_buffer(ctx); if (!more_data || ctx->input_buffer.size < 4+2) { return DE265_ERROR_EOF; } } // reserve enough space so that complete input would fit into output buffer rbsp_buffer_resize(buffer, ctx->input_buffer.size); unsigned char* out = buffer->data; int in_idx =0; int out_idx=0; // check for start-code at the beginning unsigned char* in = ctx->input_buffer.data; while (in[in_idx+0]==0 && in[in_idx+1]==0 && in[in_idx+2]==0) { in_idx++; if (ctx->input_buffer.size < in_idx+4+2) { return DE265_ERROR_EOF; } } if (in[in_idx+0] != 0 || in[in_idx+1] != 0 || in[in_idx+2] != 1) { return DE265_ERROR_NO_STARTCODE; } in_idx+=3; // copy NAL header out[out_idx++] = in[in_idx++]; out[out_idx++] = in[in_idx++]; // copy until next start-code (removing start-code emulation prevention bytes) for (;;) { // when we approach the end of the input buffer, resize (both) buffers if (ctx->input_buffer.size < in_idx+4) { bool more_data = ctx->refill_buffer(ctx); in = ctx->input_buffer.data; if (!more_data) { assert(ctx->input_buffer.size - in_idx < 4); buffer->size = out_idx; rbsp_buffer_resize(buffer, buffer->size+4); // space for up to 4 more bytes out = buffer->data; // copy remaining data to output while (in_idx < ctx->input_buffer.size) { out[out_idx++] = in[in_idx++]; } ctx->input_buffer.size = 0; // we read all data buffer->size = out_idx; return DE265_OK; } // make space such that all input data would possibly fit into the output int remaining_input_data = ctx->input_buffer.size - in_idx; buffer->size = out_idx; rbsp_buffer_resize(buffer, buffer->size + remaining_input_data); out = buffer->data; } // check for next start-code if (in[in_idx+0]==0 && in[in_idx+1]==0 && in[in_idx+2]==1) { // remove read data from input buffer memmove(ctx->input_buffer.data, ctx->input_buffer.data + in_idx, ctx->input_buffer.size - in_idx); ctx->input_buffer.size -= in_idx; buffer->size = out_idx; return DE265_OK; } // check for start-code emulation if (in[in_idx+0]==0 && in[in_idx+1]==0 && in[in_idx+2]==3) { assert(out_idx+2 <= buffer->capacity); out[out_idx++] = in[in_idx++]; out[out_idx++] = in[in_idx++]; in_idx++; // skip start-code emulation byte } else { assert(out_idx+1 <= buffer->capacity); out[out_idx++] = in[in_idx++]; } } }
LIBDE265_API de265_error de265_push_data(de265_decoder_context* de265ctx, const void* data8, int len, de265_PTS pts, void* user_data) { decoder_context* ctx = (decoder_context*)de265ctx; uint8_t* data = (uint8_t*)data8; if (ctx->pending_input_NAL == NULL) { ctx->pending_input_NAL = alloc_NAL_unit(ctx, len+3, DE265_SKIPPED_BYTES_INITIAL_SIZE); ctx->pending_input_NAL->pts = pts; ctx->pending_input_NAL->user_data = user_data; } NAL_unit* nal = ctx->pending_input_NAL; // shortcut // Resize output buffer so that complete input would fit. // We add 3, because in the worst case 3 extra bytes are created for an input byte. rbsp_buffer_resize(&nal->nal_data, nal->nal_data.size + len + 3); unsigned char* out = nal->nal_data.data + nal->nal_data.size; for (int i=0;i<len;i++) { /* printf("state=%d input=%02x (%p) (output size: %d)\n",ctx->input_push_state, *data, data, out - ctx->nal_data.data); */ switch (ctx->input_push_state) { case 0: case 1: if (*data == 0) { ctx->input_push_state++; } else { ctx->input_push_state=0; } break; case 2: if (*data == 1) { ctx->input_push_state=3; nal->num_skipped_bytes=0; } else if (*data == 0) { } // *out++ = 0; } else { ctx->input_push_state=0; } break; case 3: *out++ = *data; ctx->input_push_state = 4; break; case 4: *out++ = *data; ctx->input_push_state = 5; break; case 5: if (*data==0) { ctx->input_push_state=6; } else { *out++ = *data; } break; case 6: if (*data==0) { ctx->input_push_state=7; } else { *out++ = 0; *out++ = *data; ctx->input_push_state=5; } break; case 7: if (*data==0) { *out++ = 0; } else if (*data==3) { *out++ = 0; *out++ = 0; ctx->input_push_state=5; // remember which byte we removed nal_insert_skipped_byte(nal, (out - nal->nal_data.data) + nal->num_skipped_bytes); } else if (*data==1) { #if DEBUG_INSERT_STREAM_ERRORS if ((rand()%100)<90 && ctx->nal_data.size>0) { int pos = rand()%ctx->nal_data.size; int bit = rand()%8; nal->nal_data.data[pos] ^= 1<<bit; //printf("inserted error...\n"); } #endif nal->nal_data.size = out - nal->nal_data.data; // push this NAL decoder queue push_to_NAL_queue(ctx, nal); // initialize new, empty NAL unit ctx->pending_input_NAL = alloc_NAL_unit(ctx, len+3, DE265_SKIPPED_BYTES_INITIAL_SIZE); ctx->pending_input_NAL->pts = pts; nal = ctx->pending_input_NAL; out = nal->nal_data.data; ctx->input_push_state=3; nal->num_skipped_bytes=0; } else { *out++ = 0; *out++ = 0; *out++ = *data; ctx->input_push_state=5; } break; } data++; } nal->nal_data.size = out - nal->nal_data.data; return DE265_OK; }