de265_error de265_decode_NAL(de265_decoder_context* de265ctx, rbsp_buffer* data) { decoder_context* ctx = (decoder_context*)de265ctx; /* if (ctx->num_skipped_bytes>0) { printf("skipped bytes:\n "); for (int i=0;i<ctx->num_skipped_bytes;i++) printf("%d ",ctx->skipped_bytes[i]); printf("\n"); } */ de265_error err = DE265_OK; bitreader reader; bitreader_init(&reader, data); nal_header nal_hdr; nal_read_header(&reader, &nal_hdr); process_nal_hdr(ctx, &nal_hdr); logdebug(LogHighlevel,"NAL: 0x%x 0x%x - %d %d\n", data->data[0], data->data[1], nal_hdr.nal_unit_type, nal_hdr.nuh_temporal_id); if (nal_hdr.nal_unit_type<32) { logdebug(LogHeaders,"---> read slice segment header\n"); int sliceIndex = get_next_slice_index(ctx); slice_segment_header* hdr = &ctx->slice[sliceIndex]; hdr->slice_index = sliceIndex; read_slice_segment_header(&reader,hdr,ctx); dump_slice_segment_header(hdr, ctx); if ((err = process_slice_segment_header(ctx, hdr)) != DE265_OK) { return err; } skip_bits(&reader,1); // TODO: why? prepare_for_CABAC(&reader); // modify entry_point_offsets int headerLength = reader.data - data->data; for (int i=0;i<ctx->num_skipped_bytes;i++) { ctx->skipped_bytes[i] -= headerLength; } for (int i=0;i<hdr->num_entry_point_offsets;i++) { for (int k=ctx->num_skipped_bytes-1;k>=0;k--) if (ctx->skipped_bytes[k] <= hdr->entry_point_offset[i]) { hdr->entry_point_offset[i] -= k+1; break; } } int nRows = hdr->num_entry_point_offsets +1; bool use_WPP = (ctx->num_worker_threads > 0 && ctx->current_pps->entropy_coding_sync_enabled_flag); if (ctx->num_worker_threads > 0 && ctx->current_pps->entropy_coding_sync_enabled_flag == false) { add_warning(ctx, DE265_WARNING_NO_WPP_CANNOT_USE_MULTITHREADING, true); } if (!use_WPP) { init_thread_context(&hdr->thread_context[0]); init_CABAC_decoder(&hdr->thread_context[0].cabac_decoder, reader.data, reader.bytes_remaining); hdr->thread_context[0].shdr = hdr; hdr->thread_context[0].decctx = ctx; // fixed context 0 if ((err=read_slice_segment_data(ctx, &hdr->thread_context[0])) != DE265_OK) { return err; } } else { for (int i=0;i<nRows;i++) { int dataStartIndex; if (i==0) { dataStartIndex=0; } else { dataStartIndex=hdr->entry_point_offset[i-1]; } int dataEnd; if (i==nRows-1) dataEnd = reader.bytes_remaining; else dataEnd = hdr->entry_point_offset[i]; init_thread_context(&hdr->thread_context[i]); init_CABAC_decoder(&hdr->thread_context[i].cabac_decoder, &reader.data[dataStartIndex], dataEnd-dataStartIndex); hdr->thread_context[i].shdr = hdr; hdr->thread_context[i].decctx = ctx; } // TODO: hard-coded thread context add_CTB_decode_task_syntax(&hdr->thread_context[0], 0,0 ,0,0, NULL); /* for (int x=0;x<ctx->current_sps->PicWidthInCtbsY;x++) for (int y=0;y<ctx->current_sps->PicHeightInCtbsY;y++) { add_CTB_decode_task_syntax(&hdr->thread_context[y], x,y); } */ flush_thread_pool(&ctx->thread_pool); } } else switch (nal_hdr.nal_unit_type) { case NAL_UNIT_VPS_NUT: { logdebug(LogHeaders,"---> read VPS\n"); video_parameter_set vps; read_vps(&reader,&vps); dump_vps(&vps); process_vps(ctx, &vps); } break; case NAL_UNIT_SPS_NUT: { logdebug(LogHeaders,"----> read SPS\n"); seq_parameter_set sps; if ((err=read_sps(&reader,&sps, &ctx->ref_pic_sets)) != DE265_OK) { break; } dump_sps(&sps, ctx->ref_pic_sets); process_sps(ctx, &sps); } break; case NAL_UNIT_PPS_NUT: { logdebug(LogHeaders,"----> read PPS\n"); pic_parameter_set pps; init_pps(&pps); read_pps(&reader,&pps,ctx); dump_pps(&pps); process_pps(ctx,&pps); } break; case NAL_UNIT_PREFIX_SEI_NUT: case NAL_UNIT_SUFFIX_SEI_NUT: logdebug(LogHeaders,"----> read SEI\n"); sei_message sei; push_current_picture_to_output_queue(ctx); read_sei(&reader,&sei, nal_hdr.nal_unit_type==NAL_UNIT_SUFFIX_SEI_NUT, ctx); dump_sei(&sei, ctx); err = process_sei(&sei, ctx); break; } return err; }
de265_error de265_decode_NAL(de265_decoder_context* de265ctx, NAL_unit* nal) { decoder_context* ctx = (decoder_context*)de265ctx; rbsp_buffer* data = &nal->nal_data; de265_error err = DE265_OK; bitreader reader; bitreader_init(&reader, data); nal_header nal_hdr; nal_read_header(&reader, &nal_hdr); process_nal_hdr(ctx, &nal_hdr); loginfo(LogHighlevel,"NAL: 0x%x 0x%x - unit type:%s temporal id:%d\n", data->data[0], data->data[1], get_NAL_name(nal_hdr.nal_unit_type), nal_hdr.nuh_temporal_id); if (nal_hdr.nal_unit_type<32) { logdebug(LogHeaders,"---> read slice segment header\n"); //printf("-------- slice header --------\n"); int sliceIndex = get_next_slice_index(ctx); if (sliceIndex<0) { add_warning(ctx,DE265_ERROR_MAX_NUMBER_OF_SLICES_EXCEEDED, true); return DE265_ERROR_MAX_NUMBER_OF_SLICES_EXCEEDED; } slice_segment_header* hdr = &ctx->slice[sliceIndex]; bool continueDecoding; err = read_slice_segment_header(&reader,hdr,ctx, &continueDecoding); if (!continueDecoding) { return err; } else { hdr->slice_index = sliceIndex; if (ctx->param_slice_headers_fd>=0) { dump_slice_segment_header(hdr, ctx, ctx->param_slice_headers_fd); } if (process_slice_segment_header(ctx, hdr, &err, nal->pts, nal->user_data) == false) { ctx->img->integrity = INTEGRITY_NOT_DECODED; return err; } skip_bits(&reader,1); // TODO: why? prepare_for_CABAC(&reader); // modify entry_point_offsets int headerLength = reader.data - data->data; for (int i=0;i<nal->num_skipped_bytes;i++) { nal->skipped_bytes[i] -= headerLength; } for (int i=0;i<hdr->num_entry_point_offsets;i++) { for (int k=nal->num_skipped_bytes-1;k>=0;k--) if (nal->skipped_bytes[k] <= hdr->entry_point_offset[i]) { hdr->entry_point_offset[i] -= k+1; break; } } const pic_parameter_set* pps = ctx->current_pps; int ctbsWidth = ctx->current_sps->PicWidthInCtbsY; int nRows = hdr->num_entry_point_offsets +1; bool use_WPP = (ctx->num_worker_threads > 0 && ctx->current_pps->entropy_coding_sync_enabled_flag); bool use_tiles = (ctx->num_worker_threads > 0 && ctx->current_pps->tiles_enabled_flag); if (use_WPP && use_tiles) { //add_warning(ctx, DE265_WARNING_STREAMS_APPLIES_TILES_AND_WPP, true); } if (ctx->num_worker_threads > 0 && ctx->current_pps->entropy_coding_sync_enabled_flag == false && ctx->current_pps->tiles_enabled_flag == false) { // TODO: new error should be: no WPP and no Tiles ... add_warning(ctx, DE265_WARNING_NO_WPP_CANNOT_USE_MULTITHREADING, true); } if (!use_WPP && !use_tiles) { // --- single threaded decoding --- #if 0 int thread_context_idx = get_next_thread_context_index(ctx); if (thread_context_idx<0) { assert(false); // TODO } #else int thread_context_idx=0; #endif thread_context* tctx = &ctx->thread_context[thread_context_idx]; init_thread_context(tctx); init_CABAC_decoder(&tctx->cabac_decoder, reader.data, reader.bytes_remaining); tctx->shdr = hdr; tctx->decctx = ctx; tctx->CtbAddrInTS = pps->CtbAddrRStoTS[hdr->slice_segment_address]; // fixed context 0 if ((err=read_slice_segment_data(ctx, tctx)) != DE265_OK) { return err; } } else if (use_tiles && !use_WPP) { int nTiles = nRows; // TODO: rename 'nRows' if (nTiles > MAX_THREAD_CONTEXTS) { return DE265_ERROR_MAX_THREAD_CONTEXTS_EXCEEDED; } assert(nTiles == pps->num_tile_columns * pps->num_tile_rows); // TODO: handle other cases assert(ctx->img->tasks_pending == 0); increase_pending_tasks(ctx->img, nTiles); for (int ty=0;ty<pps->num_tile_rows;ty++) for (int tx=0;tx<pps->num_tile_columns;tx++) { int tile = tx + ty*pps->num_tile_columns; // set thread context ctx->thread_context[tile].shdr = hdr; ctx->thread_context[tile].decctx = ctx; ctx->thread_context[tile].CtbAddrInTS = pps->CtbAddrRStoTS[pps->colBd[tx] + pps->rowBd[ty]*ctbsWidth]; // init CABAC int dataStartIndex; if (tile==0) { dataStartIndex=0; } else { dataStartIndex=hdr->entry_point_offset[tile-1]; } int dataEnd; if (tile==nRows-1) dataEnd = reader.bytes_remaining; else dataEnd = hdr->entry_point_offset[tile]; init_thread_context(&ctx->thread_context[tile]); init_CABAC_decoder(&ctx->thread_context[tile].cabac_decoder, &reader.data[dataStartIndex], dataEnd-dataStartIndex); } // add tasks for (int i=0;i<nTiles;i++) { add_task_decode_slice_segment(ctx, i); } wait_for_completion(ctx->img); } else { if (nRows > MAX_THREAD_CONTEXTS) { return DE265_ERROR_MAX_THREAD_CONTEXTS_EXCEEDED; } assert(ctx->img->tasks_pending == 0); increase_pending_tasks(ctx->img, nRows); //printf("-------- decode --------\n"); for (int y=0;y<nRows;y++) { // set thread context for (int x=0;x<ctbsWidth;x++) { ctx->img->ctb_info[x+y*ctbsWidth].thread_context_id = y; // TODO: shouldn't be hardcoded } ctx->thread_context[y].shdr = hdr; ctx->thread_context[y].decctx = ctx; ctx->thread_context[y].CtbAddrInTS = pps->CtbAddrRStoTS[0 + y*ctbsWidth]; // init CABAC int dataStartIndex; if (y==0) { dataStartIndex=0; } else { dataStartIndex=hdr->entry_point_offset[y-1]; } int dataEnd; if (y==nRows-1) dataEnd = reader.bytes_remaining; else dataEnd = hdr->entry_point_offset[y]; init_thread_context(&ctx->thread_context[y]); init_CABAC_decoder(&ctx->thread_context[y].cabac_decoder, &reader.data[dataStartIndex], dataEnd-dataStartIndex); } // add tasks for (int y=0;y<nRows;y++) { add_task_decode_CTB_row(ctx, y, y==0); } wait_for_completion(ctx->img); } } } else switch (nal_hdr.nal_unit_type) { case NAL_UNIT_VPS_NUT: { logdebug(LogHeaders,"---> read VPS\n"); video_parameter_set vps; err=read_vps(ctx,&reader,&vps); if (err != DE265_OK) { break; } if (ctx->param_vps_headers_fd>=0) { dump_vps(&vps, ctx->param_vps_headers_fd); } process_vps(ctx, &vps); } break; case NAL_UNIT_SPS_NUT: { logdebug(LogHeaders,"----> read SPS\n"); seq_parameter_set sps; init_sps(&sps); if ((err=read_sps(ctx, &reader,&sps)) != DE265_OK) { break; } if (ctx->param_sps_headers_fd>=0) { dump_sps(&sps, ctx->param_sps_headers_fd); } process_sps(ctx, &sps); } break; case NAL_UNIT_PPS_NUT: { logdebug(LogHeaders,"----> read PPS\n"); pic_parameter_set pps; init_pps(&pps); bool success = read_pps(&reader,&pps,ctx); if (ctx->param_pps_headers_fd>=0) { dump_pps(&pps, ctx->param_pps_headers_fd); } if (success) { process_pps(ctx,&pps); } } break; case NAL_UNIT_PREFIX_SEI_NUT: case NAL_UNIT_SUFFIX_SEI_NUT: logdebug(LogHeaders,"----> read SEI\n"); sei_message sei; push_current_picture_to_output_queue(ctx); if (read_sei(&reader,&sei, nal_hdr.nal_unit_type==NAL_UNIT_SUFFIX_SEI_NUT, ctx)) { dump_sei(&sei, ctx); err = process_sei(&sei, ctx); } break; case NAL_UNIT_EOS_NUT: ctx->FirstAfterEndOfSequenceNAL = true; break; } return err; }