You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
711 lines
20 KiB
711 lines
20 KiB
/*
|
|
* H.265 video codec.
|
|
* Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
|
|
*
|
|
* This file is part of libde265.
|
|
*
|
|
* libde265 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation, either version 3 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* libde265 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with libde265. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define DEBUG_INSERT_STREAM_ERRORS 0
|
|
|
|
|
|
#include "de265.h"
|
|
#include "decctx.h"
|
|
#include "util.h"
|
|
#include "scan.h"
|
|
#include "image.h"
|
|
#include "sei.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <mutex>
|
|
|
|
|
|
// TODO: should be in some vps.c related header
|
|
de265_error read_vps(decoder_context* ctx, bitreader* reader, video_parameter_set* vps);
|
|
|
|
extern "C" {
|
|
LIBDE265_API const char *de265_get_version(void)
|
|
{
|
|
return (LIBDE265_VERSION);
|
|
}
|
|
|
|
LIBDE265_API uint32_t de265_get_version_number(void)
|
|
{
|
|
return (LIBDE265_NUMERIC_VERSION);
|
|
}
|
|
|
|
LIBDE265_API int de265_get_version_number_major(void)
|
|
{
|
|
return ((LIBDE265_NUMERIC_VERSION)>>24) & 0xFF;
|
|
}
|
|
|
|
LIBDE265_API int de265_get_version_number_minor(void)
|
|
{
|
|
return ((LIBDE265_NUMERIC_VERSION)>>16) & 0xFF;
|
|
}
|
|
|
|
LIBDE265_API int de265_get_version_number_maintenance(void)
|
|
{
|
|
return ((LIBDE265_NUMERIC_VERSION)>>8) & 0xFF;
|
|
}
|
|
|
|
|
|
LIBDE265_API const char* de265_get_error_text(de265_error err)
|
|
{
|
|
switch (err) {
|
|
case DE265_OK: return "no error";
|
|
case DE265_ERROR_NO_SUCH_FILE: return "no such file";
|
|
//case DE265_ERROR_NO_STARTCODE: return "no startcode found";
|
|
//case DE265_ERROR_EOF: return "end of file";
|
|
case DE265_ERROR_COEFFICIENT_OUT_OF_IMAGE_BOUNDS: return "coefficient out of image bounds";
|
|
case DE265_ERROR_CHECKSUM_MISMATCH: return "image checksum mismatch";
|
|
case DE265_ERROR_CTB_OUTSIDE_IMAGE_AREA: return "CTB outside of image area";
|
|
case DE265_ERROR_OUT_OF_MEMORY: return "out of memory";
|
|
case DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE: return "coded parameter out of range";
|
|
case DE265_ERROR_IMAGE_BUFFER_FULL: return "DPB/output queue full";
|
|
case DE265_ERROR_CANNOT_START_THREADPOOL: return "cannot start decoding threads";
|
|
case DE265_ERROR_LIBRARY_INITIALIZATION_FAILED: return "global library initialization failed";
|
|
case DE265_ERROR_LIBRARY_NOT_INITIALIZED: return "cannot free library data (not initialized";
|
|
|
|
//case DE265_ERROR_MAX_THREAD_CONTEXTS_EXCEEDED:
|
|
// return "internal error: maximum number of thread contexts exceeded";
|
|
//case DE265_ERROR_MAX_NUMBER_OF_SLICES_EXCEEDED:
|
|
// return "internal error: maximum number of slices exceeded";
|
|
case DE265_ERROR_NOT_IMPLEMENTED_YET:
|
|
return "unimplemented decoder feature";
|
|
//case DE265_ERROR_SCALING_LIST_NOT_IMPLEMENTED:
|
|
//return "scaling list not implemented";
|
|
|
|
case DE265_ERROR_WAITING_FOR_INPUT_DATA:
|
|
return "no more input data, decoder stalled";
|
|
case DE265_ERROR_CANNOT_PROCESS_SEI:
|
|
return "SEI data cannot be processed";
|
|
case DE265_ERROR_PARAMETER_PARSING:
|
|
return "command-line parameter error";
|
|
case DE265_ERROR_NO_INITIAL_SLICE_HEADER:
|
|
return "first slice missing, cannot decode dependent slice";
|
|
case DE265_ERROR_PREMATURE_END_OF_SLICE:
|
|
return "premature end of slice data";
|
|
case DE265_ERROR_UNSPECIFIED_DECODING_ERROR:
|
|
return "unspecified decoding error";
|
|
|
|
case DE265_WARNING_NO_WPP_CANNOT_USE_MULTITHREADING:
|
|
return "Cannot run decoder multi-threaded because stream does not support WPP";
|
|
case DE265_WARNING_WARNING_BUFFER_FULL:
|
|
return "Too many warnings queued";
|
|
case DE265_WARNING_PREMATURE_END_OF_SLICE_SEGMENT:
|
|
return "Premature end of slice segment";
|
|
case DE265_WARNING_INCORRECT_ENTRY_POINT_OFFSET:
|
|
return "Incorrect entry-point offsets";
|
|
case DE265_WARNING_CTB_OUTSIDE_IMAGE_AREA:
|
|
return "CTB outside of image area (concealing stream error...)";
|
|
case DE265_WARNING_SPS_HEADER_INVALID:
|
|
return "sps header invalid";
|
|
case DE265_WARNING_PPS_HEADER_INVALID:
|
|
return "pps header invalid";
|
|
case DE265_WARNING_SLICEHEADER_INVALID:
|
|
return "slice header invalid";
|
|
case DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING:
|
|
return "impossible motion vector scaling";
|
|
case DE265_WARNING_NONEXISTING_PPS_REFERENCED:
|
|
return "non-existing PPS referenced";
|
|
case DE265_WARNING_NONEXISTING_SPS_REFERENCED:
|
|
return "non-existing SPS referenced";
|
|
case DE265_WARNING_BOTH_PREDFLAGS_ZERO:
|
|
return "both predFlags[] are zero in MC";
|
|
case DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED:
|
|
return "non-existing reference picture accessed";
|
|
case DE265_WARNING_NUMMVP_NOT_EQUAL_TO_NUMMVQ:
|
|
return "numMV_P != numMV_Q in deblocking";
|
|
case DE265_WARNING_NUMBER_OF_SHORT_TERM_REF_PIC_SETS_OUT_OF_RANGE:
|
|
return "number of short-term ref-pic-sets out of range";
|
|
case DE265_WARNING_SHORT_TERM_REF_PIC_SET_OUT_OF_RANGE:
|
|
return "short-term ref-pic-set index out of range";
|
|
case DE265_WARNING_FAULTY_REFERENCE_PICTURE_LIST:
|
|
return "faulty reference picture list";
|
|
case DE265_WARNING_EOSS_BIT_NOT_SET:
|
|
return "end_of_sub_stream_one_bit not set to 1 when it should be";
|
|
case DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED:
|
|
return "maximum number of reference pictures exceeded";
|
|
case DE265_WARNING_INVALID_CHROMA_FORMAT:
|
|
return "invalid chroma format in SPS header";
|
|
case DE265_WARNING_SLICE_SEGMENT_ADDRESS_INVALID:
|
|
return "slice segment address invalid";
|
|
case DE265_WARNING_DEPENDENT_SLICE_WITH_ADDRESS_ZERO:
|
|
return "dependent slice with address 0";
|
|
case DE265_WARNING_NUMBER_OF_THREADS_LIMITED_TO_MAXIMUM:
|
|
return "number of threads limited to maximum amount";
|
|
case DE265_NON_EXISTING_LT_REFERENCE_CANDIDATE_IN_SLICE_HEADER:
|
|
return "non-existing long-term reference candidate specified in slice header";
|
|
case DE265_WARNING_CANNOT_APPLY_SAO_OUT_OF_MEMORY:
|
|
return "cannot apply SAO because we ran out of memory";
|
|
case DE265_WARNING_SPS_MISSING_CANNOT_DECODE_SEI:
|
|
return "SPS header missing, cannot decode SEI";
|
|
case DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA:
|
|
return "collocated motion-vector is outside image area";
|
|
|
|
default: return "unknown error";
|
|
}
|
|
}
|
|
|
|
LIBDE265_API int de265_isOK(de265_error err)
|
|
{
|
|
return err == DE265_OK || err >= 1000;
|
|
}
|
|
|
|
|
|
|
|
static int de265_init_count;
|
|
|
|
static std::mutex de265_init_mutex;
|
|
|
|
|
|
LIBDE265_API de265_error de265_init()
|
|
{
|
|
std::lock_guard<std::mutex> lock(de265_init_mutex);
|
|
|
|
de265_init_count++;
|
|
|
|
if (de265_init_count > 1) {
|
|
// we are not the first -> already initialized
|
|
|
|
return DE265_OK;
|
|
}
|
|
|
|
|
|
// do initializations
|
|
|
|
init_scan_orders();
|
|
|
|
if (!alloc_and_init_significant_coeff_ctxIdx_lookupTable()) {
|
|
de265_init_count--;
|
|
return DE265_ERROR_LIBRARY_INITIALIZATION_FAILED;
|
|
}
|
|
|
|
return DE265_OK;
|
|
}
|
|
|
|
LIBDE265_API de265_error de265_free()
|
|
{
|
|
std::lock_guard<std::mutex> lock(de265_init_mutex);
|
|
|
|
if (de265_init_count<=0) {
|
|
return DE265_ERROR_LIBRARY_NOT_INITIALIZED;
|
|
}
|
|
|
|
de265_init_count--;
|
|
|
|
if (de265_init_count==0) {
|
|
free_significant_coeff_ctxIdx_lookupTable();
|
|
}
|
|
|
|
return DE265_OK;
|
|
}
|
|
|
|
|
|
LIBDE265_API de265_decoder_context* de265_new_decoder()
|
|
{
|
|
de265_error init_err = de265_init();
|
|
if (init_err != DE265_OK) {
|
|
return NULL;
|
|
}
|
|
|
|
decoder_context* ctx = new decoder_context;
|
|
if (!ctx) {
|
|
de265_free();
|
|
return NULL;
|
|
}
|
|
|
|
return (de265_decoder_context*)ctx;
|
|
}
|
|
|
|
|
|
LIBDE265_API de265_error de265_free_decoder(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
ctx->stop_thread_pool();
|
|
|
|
delete ctx;
|
|
|
|
return de265_free();
|
|
}
|
|
|
|
|
|
LIBDE265_API de265_error de265_start_worker_threads(de265_decoder_context* de265ctx, int number_of_threads)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
if (number_of_threads > MAX_THREADS) {
|
|
number_of_threads = MAX_THREADS;
|
|
}
|
|
|
|
if (number_of_threads>0) {
|
|
de265_error err = ctx->start_thread_pool(number_of_threads);
|
|
if (de265_isOK(err)) {
|
|
err = DE265_OK;
|
|
}
|
|
return err;
|
|
}
|
|
else {
|
|
return DE265_OK;
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef LIBDE265_DISABLE_DEPRECATED
|
|
LIBDE265_API de265_error de265_decode_data(de265_decoder_context* de265ctx,
|
|
const void* data8, int len)
|
|
{
|
|
//decoder_context* ctx = (decoder_context*)de265ctx;
|
|
de265_error err;
|
|
if (len > 0) {
|
|
err = de265_push_data(de265ctx, data8, len, 0, NULL);
|
|
} else {
|
|
err = de265_flush_data(de265ctx);
|
|
}
|
|
if (err != DE265_OK) {
|
|
return err;
|
|
}
|
|
|
|
int more = 0;
|
|
do {
|
|
err = de265_decode(de265ctx, &more);
|
|
if (err != DE265_OK) {
|
|
more = 0;
|
|
}
|
|
|
|
switch (err) {
|
|
case DE265_ERROR_WAITING_FOR_INPUT_DATA:
|
|
// ignore error (didn't exist in 0.4 and before)
|
|
err = DE265_OK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} while (more);
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
static void dumpdata(const void* data, int len)
|
|
{
|
|
for (int i=0;i<len;i++) {
|
|
printf("%02x ", ((uint8_t*)data)[i]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
//printf("push data (size %d)\n",len);
|
|
//dumpdata(data8,16);
|
|
|
|
return ctx->nal_parser.push_data(data,len,pts,user_data);
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
//printf("push NAL (size %d)\n",len);
|
|
//dumpdata(data8,16);
|
|
|
|
return ctx->nal_parser.push_NAL(data,len,pts,user_data);
|
|
}
|
|
|
|
|
|
LIBDE265_API de265_error de265_decode(de265_decoder_context* de265ctx, int* more)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
return ctx->decode(more);
|
|
}
|
|
|
|
|
|
LIBDE265_API void de265_push_end_of_NAL(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
ctx->nal_parser.flush_data();
|
|
}
|
|
|
|
|
|
LIBDE265_API void de265_push_end_of_frame(de265_decoder_context* de265ctx)
|
|
{
|
|
de265_push_end_of_NAL(de265ctx);
|
|
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
ctx->nal_parser.mark_end_of_frame();
|
|
}
|
|
|
|
|
|
LIBDE265_API de265_error de265_flush_data(de265_decoder_context* de265ctx)
|
|
{
|
|
de265_push_end_of_NAL(de265ctx);
|
|
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
ctx->nal_parser.flush_data();
|
|
ctx->nal_parser.mark_end_of_stream();
|
|
|
|
return DE265_OK;
|
|
}
|
|
|
|
|
|
LIBDE265_API void de265_reset(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
//printf("--- reset ---\n");
|
|
|
|
ctx->reset();
|
|
}
|
|
|
|
|
|
LIBDE265_API const struct de265_image* de265_get_next_picture(de265_decoder_context* de265ctx)
|
|
{
|
|
const struct de265_image* img = de265_peek_next_picture(de265ctx);
|
|
if (img) {
|
|
de265_release_next_picture(de265ctx);
|
|
}
|
|
|
|
return img;
|
|
}
|
|
|
|
|
|
LIBDE265_API const struct de265_image* de265_peek_next_picture(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
if (ctx->num_pictures_in_output_queue()>0) {
|
|
de265_image* img = ctx->get_next_picture_in_output_queue();
|
|
return img;
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
LIBDE265_API void de265_release_next_picture(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
// no active output picture -> ignore release request
|
|
|
|
if (ctx->num_pictures_in_output_queue()==0) { return; }
|
|
|
|
de265_image* next_image = ctx->get_next_picture_in_output_queue();
|
|
|
|
loginfo(LogDPB, "release DPB with POC=%d\n",next_image->PicOrderCntVal);
|
|
|
|
next_image->PicOutputFlag = false;
|
|
|
|
// TODO: actually, we want to release it here, but we cannot without breaking API
|
|
// compatibility, because get_next_picture calls this immediately. Hence, we release
|
|
// images while scanning for available slots in the DPB.
|
|
// if (next_image->can_be_released()) { next_image->release(); }
|
|
|
|
// pop output queue
|
|
|
|
ctx->pop_next_picture_in_output_queue();
|
|
}
|
|
|
|
|
|
|
|
LIBDE265_API int de265_get_highest_TID(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
return ctx->get_highest_TID();
|
|
}
|
|
|
|
LIBDE265_API int de265_get_current_TID(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
return ctx->get_current_TID();
|
|
}
|
|
|
|
LIBDE265_API void de265_set_limit_TID(de265_decoder_context* de265ctx,int max_tid)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
ctx->set_limit_TID(max_tid);
|
|
}
|
|
|
|
LIBDE265_API void de265_set_framerate_ratio(de265_decoder_context* de265ctx,int percent)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
ctx->set_framerate_ratio(percent);
|
|
}
|
|
|
|
LIBDE265_API int de265_change_framerate(de265_decoder_context* de265ctx,int more)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
return ctx->change_framerate(more);
|
|
}
|
|
|
|
|
|
LIBDE265_API de265_error de265_get_warning(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
return ctx->get_warning();
|
|
}
|
|
|
|
LIBDE265_API void de265_set_parameter_bool(de265_decoder_context* de265ctx, enum de265_param param, int value)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
switch (param)
|
|
{
|
|
case DE265_DECODER_PARAM_BOOL_SEI_CHECK_HASH:
|
|
ctx->param_sei_check_hash = !!value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_SUPPRESS_FAULTY_PICTURES:
|
|
ctx->param_suppress_faulty_pictures = !!value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_DISABLE_DEBLOCKING:
|
|
ctx->param_disable_deblocking = !!value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_DISABLE_SAO:
|
|
ctx->param_disable_sao = !!value;
|
|
break;
|
|
|
|
/*
|
|
case DE265_DECODER_PARAM_DISABLE_MC_RESIDUAL_IDCT:
|
|
ctx->param_disable_mc_residual_idct = !!value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_DISABLE_INTRA_RESIDUAL_IDCT:
|
|
ctx->param_disable_intra_residual_idct = !!value;
|
|
break;
|
|
*/
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
LIBDE265_API void de265_set_parameter_int(de265_decoder_context* de265ctx, enum de265_param param, int value)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
switch (param)
|
|
{
|
|
case DE265_DECODER_PARAM_DUMP_SPS_HEADERS:
|
|
ctx->param_sps_headers_fd = value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_DUMP_VPS_HEADERS:
|
|
ctx->param_vps_headers_fd = value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_DUMP_PPS_HEADERS:
|
|
ctx->param_pps_headers_fd = value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_DUMP_SLICE_HEADERS:
|
|
ctx->param_slice_headers_fd = value;
|
|
break;
|
|
|
|
case DE265_DECODER_PARAM_ACCELERATION_CODE:
|
|
ctx->set_acceleration_functions((enum de265_acceleration)value);
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
LIBDE265_API int de265_get_parameter_bool(de265_decoder_context* de265ctx, enum de265_param param)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
switch (param)
|
|
{
|
|
case DE265_DECODER_PARAM_BOOL_SEI_CHECK_HASH:
|
|
return ctx->param_sei_check_hash;
|
|
|
|
case DE265_DECODER_PARAM_SUPPRESS_FAULTY_PICTURES:
|
|
return ctx->param_suppress_faulty_pictures;
|
|
|
|
case DE265_DECODER_PARAM_DISABLE_DEBLOCKING:
|
|
return ctx->param_disable_deblocking;
|
|
|
|
case DE265_DECODER_PARAM_DISABLE_SAO:
|
|
return ctx->param_disable_sao;
|
|
|
|
/*
|
|
case DE265_DECODER_PARAM_DISABLE_MC_RESIDUAL_IDCT:
|
|
return ctx->param_disable_mc_residual_idct;
|
|
|
|
case DE265_DECODER_PARAM_DISABLE_INTRA_RESIDUAL_IDCT:
|
|
return ctx->param_disable_intra_residual_idct;
|
|
*/
|
|
|
|
default:
|
|
assert(false);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
LIBDE265_API int de265_get_number_of_input_bytes_pending(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
return ctx->nal_parser.bytes_in_input_queue();
|
|
}
|
|
|
|
|
|
LIBDE265_API int de265_get_number_of_NAL_units_pending(de265_decoder_context* de265ctx)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
return ctx->nal_parser.number_of_NAL_units_pending();
|
|
}
|
|
|
|
|
|
LIBDE265_API int de265_get_image_width(const struct de265_image* img,int channel)
|
|
{
|
|
switch (channel) {
|
|
case 0:
|
|
return img->width_confwin;
|
|
case 1:
|
|
case 2:
|
|
return img->chroma_width_confwin;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
LIBDE265_API int de265_get_image_height(const struct de265_image* img,int channel)
|
|
{
|
|
switch (channel) {
|
|
case 0:
|
|
return img->height_confwin;
|
|
case 1:
|
|
case 2:
|
|
return img->chroma_height_confwin;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
LIBDE265_API int de265_get_bits_per_pixel(const struct de265_image* img,int channel)
|
|
{
|
|
switch (channel) {
|
|
case 0:
|
|
return img->get_sps().BitDepth_Y;
|
|
case 1:
|
|
case 2:
|
|
return img->get_sps().BitDepth_C;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
LIBDE265_API enum de265_chroma de265_get_chroma_format(const struct de265_image* img)
|
|
{
|
|
return img->get_chroma_format();
|
|
}
|
|
|
|
LIBDE265_API const uint8_t* de265_get_image_plane(const de265_image* img, int channel, int* stride)
|
|
{
|
|
assert(channel>=0 && channel <= 2);
|
|
|
|
uint8_t* data = img->pixels_confwin[channel];
|
|
|
|
if (stride) *stride = img->get_image_stride(channel) * ((de265_get_bits_per_pixel(img, channel)+7) / 8);
|
|
|
|
return data;
|
|
}
|
|
|
|
LIBDE265_API void *de265_get_image_plane_user_data(const struct de265_image* img, int channel)
|
|
{
|
|
assert(channel>=0 && channel <= 2);
|
|
|
|
return img->plane_user_data[channel];
|
|
}
|
|
|
|
LIBDE265_API void de265_set_image_plane(de265_image* img, int cIdx, void* mem, int stride, void *userdata)
|
|
{
|
|
// The internal "stride" is the number of pixels per line.
|
|
stride = stride / ((de265_get_bits_per_pixel(img, cIdx)+7) / 8);
|
|
img->set_image_plane(cIdx, (uint8_t*)mem, stride, userdata);
|
|
}
|
|
|
|
LIBDE265_API void de265_set_image_allocation_functions(de265_decoder_context* de265ctx,
|
|
de265_image_allocation* allocfunc,
|
|
void* userdata)
|
|
{
|
|
decoder_context* ctx = (decoder_context*)de265ctx;
|
|
|
|
ctx->set_image_allocation_functions(allocfunc, userdata);
|
|
}
|
|
|
|
LIBDE265_API const struct de265_image_allocation *de265_get_default_image_allocation_functions(void)
|
|
{
|
|
return &de265_image::default_image_allocation;
|
|
}
|
|
|
|
LIBDE265_API de265_PTS de265_get_image_PTS(const struct de265_image* img)
|
|
{
|
|
return img->pts;
|
|
}
|
|
|
|
LIBDE265_API void* de265_get_image_user_data(const struct de265_image* img)
|
|
{
|
|
return img->user_data;
|
|
}
|
|
|
|
LIBDE265_API void de265_set_image_user_data(struct de265_image* img, void *user_data)
|
|
{
|
|
img->user_data = user_data;
|
|
}
|
|
|
|
LIBDE265_API void de265_get_image_NAL_header(const struct de265_image* img,
|
|
int* nal_unit_type,
|
|
const char** nal_unit_name,
|
|
int* nuh_layer_id,
|
|
int* nuh_temporal_id)
|
|
{
|
|
if (nal_unit_type) *nal_unit_type = img->nal_hdr.nal_unit_type;
|
|
if (nal_unit_name) *nal_unit_name = get_NAL_name(img->nal_hdr.nal_unit_type);
|
|
if (nuh_layer_id) *nuh_layer_id = img->nal_hdr.nuh_layer_id;
|
|
if (nuh_temporal_id) *nuh_temporal_id = img->nal_hdr.nuh_temporal_id;
|
|
}
|
|
}
|
|
|