Esempio n. 1
0
LIBDE265_API de265_error de265_decode(de265_decoder_context* de265ctx, int* more)
{
  decoder_context* ctx = (decoder_context*)de265ctx;

  // if the stream has ended, and no more NALs are to be decoded, flush all pictures

  if (ctx->NAL_queue_len == 0 && ctx->end_of_stream) {
    if (more) { *more=0; } // 0 if no more pictures in queue

    push_current_picture_to_output_queue(ctx);

    while (ctx->reorder_output_queue_length>0) {
      flush_next_picture_from_reorder_buffer(ctx);
      if (more) { *more=1; }
    }

    return DE265_OK;
  }


  // if NAL-queue is empty, we need more data
  // -> input stalled

  if (ctx->NAL_queue_len == 0) {
    if (more) { *more=1; }

    return DE265_ERROR_WAITING_FOR_INPUT_DATA;
  }


  // when there are no free image buffers in the DPB, pause decoding
  // -> output stalled

  if (!has_free_dpb_picture(ctx, false)) {
    if (more) *more = 1;
    return DE265_ERROR_IMAGE_BUFFER_FULL;
  }


  // decode one NAL from the queue

  NAL_unit* nal = pop_from_NAL_queue(ctx);
  assert(nal);
  de265_error err = de265_decode_NAL(de265ctx, nal);
  free_NAL_unit(ctx,nal);

  if (more) {
    // decoding error is assumed to be unrecoverable
    *more = (err==DE265_OK);
  }

  return err;
}
Esempio n. 2
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
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;
}