Example #1
0
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;
}
Example #2
0
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;
}