From 4f9423001723011b3a1697748aa50ad6746b0f4f Mon Sep 17 00:00:00 2001 From: Chema Gonzalez Date: Thu, 18 Apr 2019 18:34:01 -0700 Subject: [PATCH] libde265: add callback mechanism to parse events Add a mechanism that allows a decoder tool to get a callback for every NAL unit, slice content, and image that it is interested on. The idea is for the decoder tool to subscribe to the event it wants to hear about, and then get the parser object. This requires: * replace C linkage with C++ linkage, so that we can add classes in the callback * move error codes to separate file, to break the circular dependency between several files (e.g. `[sps|pps|vps].h`) and de265.h Tested: Wrote a decoder that subscribes to all the events, and just calls the `dump` method for every object. --- libde265/Makefile.am | 1 + libde265/contextmodel.h | 1 - libde265/de265-error.h | 86 ++++++++++++++++++++++++++++++++++++++++ libde265/de265.cc | 14 ++++++- libde265/de265.h | 87 ++++++++++------------------------------- libde265/decctx.cc | 30 ++++++++++++++ libde265/decctx.h | 7 ++++ libde265/en265.h | 8 ---- libde265/sps.h | 2 +- libde265/vps.h | 2 +- libde265/vui.h | 2 +- 11 files changed, 159 insertions(+), 81 deletions(-) create mode 100644 libde265/de265-error.h diff --git a/libde265/Makefile.am b/libde265/Makefile.am index 305f934a9..580a18e5a 100644 --- a/libde265/Makefile.am +++ b/libde265/Makefile.am @@ -120,4 +120,5 @@ EXTRA_DIST = Makefile.vc7 \ libde265_la_HEADERS = \ de265.h \ + de265-error.h \ de265-version.h diff --git a/libde265/contextmodel.h b/libde265/contextmodel.h index cde83e110..597d6121c 100644 --- a/libde265/contextmodel.h +++ b/libde265/contextmodel.h @@ -25,7 +25,6 @@ #define DE265_CONTEXTMODEL_H #include "libde265/cabac.h" -#include "libde265/de265.h" #include #include diff --git a/libde265/de265-error.h b/libde265/de265-error.h new file mode 100644 index 000000000..080bc6b2d --- /dev/null +++ b/libde265/de265-error.h @@ -0,0 +1,86 @@ +/* + * H.265 video codec. + * Copyright (c) 2013-2014 struktur AG, Dirk Farin + * + * 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 . +*/ + + +#ifndef DE265_ERROR_H +#define DE265_ERROR_H + +/* === error codes === */ + +typedef enum { + DE265_OK = 0, + DE265_ERROR_NO_SUCH_FILE=1, + //DE265_ERROR_NO_STARTCODE=2, obsolete + //DE265_ERROR_EOF=3, + DE265_ERROR_COEFFICIENT_OUT_OF_IMAGE_BOUNDS=4, + DE265_ERROR_CHECKSUM_MISMATCH=5, + DE265_ERROR_CTB_OUTSIDE_IMAGE_AREA=6, + DE265_ERROR_OUT_OF_MEMORY=7, + DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE=8, + DE265_ERROR_IMAGE_BUFFER_FULL=9, + DE265_ERROR_CANNOT_START_THREADPOOL=10, + DE265_ERROR_LIBRARY_INITIALIZATION_FAILED=11, + DE265_ERROR_LIBRARY_NOT_INITIALIZED=12, + DE265_ERROR_WAITING_FOR_INPUT_DATA=13, + DE265_ERROR_CANNOT_PROCESS_SEI=14, + DE265_ERROR_PARAMETER_PARSING=15, + DE265_ERROR_NO_INITIAL_SLICE_HEADER=16, + DE265_ERROR_PREMATURE_END_OF_SLICE=17, + DE265_ERROR_UNSPECIFIED_DECODING_ERROR=18, + + // --- errors that should become obsolete in later libde265 versions --- + + //DE265_ERROR_MAX_THREAD_CONTEXTS_EXCEEDED = 500, obsolete + //DE265_ERROR_MAX_NUMBER_OF_SLICES_EXCEEDED = 501, obsolete + DE265_ERROR_NOT_IMPLEMENTED_YET = 502, + //DE265_ERROR_SCALING_LIST_NOT_IMPLEMENTED = 502, obsolete + + // --- warnings --- + + DE265_WARNING_NO_WPP_CANNOT_USE_MULTITHREADING = 1000, + DE265_WARNING_WARNING_BUFFER_FULL=1001, + DE265_WARNING_PREMATURE_END_OF_SLICE_SEGMENT=1002, + DE265_WARNING_INCORRECT_ENTRY_POINT_OFFSET=1003, + DE265_WARNING_CTB_OUTSIDE_IMAGE_AREA=1004, + DE265_WARNING_SPS_HEADER_INVALID=1005, + DE265_WARNING_PPS_HEADER_INVALID=1006, + DE265_WARNING_SLICEHEADER_INVALID=1007, + DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING=1008, + DE265_WARNING_NONEXISTING_PPS_REFERENCED=1009, + DE265_WARNING_NONEXISTING_SPS_REFERENCED=1010, + DE265_WARNING_BOTH_PREDFLAGS_ZERO=1011, + DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED=1012, + DE265_WARNING_NUMMVP_NOT_EQUAL_TO_NUMMVQ=1013, + DE265_WARNING_NUMBER_OF_SHORT_TERM_REF_PIC_SETS_OUT_OF_RANGE=1014, + DE265_WARNING_SHORT_TERM_REF_PIC_SET_OUT_OF_RANGE=1015, + DE265_WARNING_FAULTY_REFERENCE_PICTURE_LIST=1016, + DE265_WARNING_EOSS_BIT_NOT_SET=1017, + DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED=1018, + DE265_WARNING_INVALID_CHROMA_FORMAT=1019, + DE265_WARNING_SLICE_SEGMENT_ADDRESS_INVALID=1020, + DE265_WARNING_DEPENDENT_SLICE_WITH_ADDRESS_ZERO=1021, + DE265_WARNING_NUMBER_OF_THREADS_LIMITED_TO_MAXIMUM=1022, + DE265_NON_EXISTING_LT_REFERENCE_CANDIDATE_IN_SLICE_HEADER=1023, + DE265_WARNING_CANNOT_APPLY_SAO_OUT_OF_MEMORY=1024, + DE265_WARNING_SPS_MISSING_CANNOT_DECODE_SEI=1025, + DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA=1026 +} de265_error; + +#endif diff --git a/libde265/de265.cc b/libde265/de265.cc index 75dd0a893..c793901e8 100644 --- a/libde265/de265.cc +++ b/libde265/de265.cc @@ -37,7 +37,6 @@ // 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); @@ -468,6 +467,18 @@ LIBDE265_API int de265_change_framerate(de265_decoder_context* de265ctx,int mor return ctx->change_framerate(more); } +LIBDE265_API void de265_callback_register(de265_decoder_context* de265ctx, de265_callback_block* cbb) +{ + decoder_context* ctx = (decoder_context*)de265ctx; + ctx->callback_register(cbb); +} + +LIBDE265_API void de265_callback_unregister(de265_decoder_context* de265ctx) +{ + decoder_context* ctx = (decoder_context*)de265ctx; + ctx->callback_unregister(); +} + LIBDE265_API de265_error de265_get_warning(de265_decoder_context* de265ctx) { @@ -708,4 +719,3 @@ LIBDE265_API void de265_get_image_NAL_header(const struct de265_image* img, 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; } -} diff --git a/libde265/de265.h b/libde265/de265.h index 6481d8f0a..af35ad949 100644 --- a/libde265/de265.h +++ b/libde265/de265.h @@ -22,9 +22,6 @@ #ifndef DE265_H #define DE265_H -#ifdef __cplusplus -extern "C" { -#endif #include @@ -66,6 +63,11 @@ extern "C" { #define LIBDE265_INLINE inline #endif +#include "de265-error.h" +#include "vps.h" +#include "pps.h" +#include "sps.h" + /* === version numbers === */ // version of linked libde265 library @@ -77,67 +79,7 @@ LIBDE265_API int de265_get_version_number_minor(void); LIBDE265_API int de265_get_version_number_maintenance(void); -/* === error codes === */ - -typedef enum { - DE265_OK = 0, - DE265_ERROR_NO_SUCH_FILE=1, - //DE265_ERROR_NO_STARTCODE=2, obsolet - //DE265_ERROR_EOF=3, - DE265_ERROR_COEFFICIENT_OUT_OF_IMAGE_BOUNDS=4, - DE265_ERROR_CHECKSUM_MISMATCH=5, - DE265_ERROR_CTB_OUTSIDE_IMAGE_AREA=6, - DE265_ERROR_OUT_OF_MEMORY=7, - DE265_ERROR_CODED_PARAMETER_OUT_OF_RANGE=8, - DE265_ERROR_IMAGE_BUFFER_FULL=9, - DE265_ERROR_CANNOT_START_THREADPOOL=10, - DE265_ERROR_LIBRARY_INITIALIZATION_FAILED=11, - DE265_ERROR_LIBRARY_NOT_INITIALIZED=12, - DE265_ERROR_WAITING_FOR_INPUT_DATA=13, - DE265_ERROR_CANNOT_PROCESS_SEI=14, - DE265_ERROR_PARAMETER_PARSING=15, - DE265_ERROR_NO_INITIAL_SLICE_HEADER=16, - DE265_ERROR_PREMATURE_END_OF_SLICE=17, - DE265_ERROR_UNSPECIFIED_DECODING_ERROR=18, - - // --- errors that should become obsolete in later libde265 versions --- - - //DE265_ERROR_MAX_THREAD_CONTEXTS_EXCEEDED = 500, obsolet - //DE265_ERROR_MAX_NUMBER_OF_SLICES_EXCEEDED = 501, obsolet - DE265_ERROR_NOT_IMPLEMENTED_YET = 502, - //DE265_ERROR_SCALING_LIST_NOT_IMPLEMENTED = 502, obsolet - - // --- warnings --- - - DE265_WARNING_NO_WPP_CANNOT_USE_MULTITHREADING = 1000, - DE265_WARNING_WARNING_BUFFER_FULL=1001, - DE265_WARNING_PREMATURE_END_OF_SLICE_SEGMENT=1002, - DE265_WARNING_INCORRECT_ENTRY_POINT_OFFSET=1003, - DE265_WARNING_CTB_OUTSIDE_IMAGE_AREA=1004, - DE265_WARNING_SPS_HEADER_INVALID=1005, - DE265_WARNING_PPS_HEADER_INVALID=1006, - DE265_WARNING_SLICEHEADER_INVALID=1007, - DE265_WARNING_INCORRECT_MOTION_VECTOR_SCALING=1008, - DE265_WARNING_NONEXISTING_PPS_REFERENCED=1009, - DE265_WARNING_NONEXISTING_SPS_REFERENCED=1010, - DE265_WARNING_BOTH_PREDFLAGS_ZERO=1011, - DE265_WARNING_NONEXISTING_REFERENCE_PICTURE_ACCESSED=1012, - DE265_WARNING_NUMMVP_NOT_EQUAL_TO_NUMMVQ=1013, - DE265_WARNING_NUMBER_OF_SHORT_TERM_REF_PIC_SETS_OUT_OF_RANGE=1014, - DE265_WARNING_SHORT_TERM_REF_PIC_SET_OUT_OF_RANGE=1015, - DE265_WARNING_FAULTY_REFERENCE_PICTURE_LIST=1016, - DE265_WARNING_EOSS_BIT_NOT_SET=1017, - DE265_WARNING_MAX_NUM_REF_PICS_EXCEEDED=1018, - DE265_WARNING_INVALID_CHROMA_FORMAT=1019, - DE265_WARNING_SLICE_SEGMENT_ADDRESS_INVALID=1020, - DE265_WARNING_DEPENDENT_SLICE_WITH_ADDRESS_ZERO=1021, - DE265_WARNING_NUMBER_OF_THREADS_LIMITED_TO_MAXIMUM=1022, - DE265_NON_EXISTING_LT_REFERENCE_CANDIDATE_IN_SLICE_HEADER=1023, - DE265_WARNING_CANNOT_APPLY_SAO_OUT_OF_MEMORY=1024, - DE265_WARNING_SPS_MISSING_CANNOT_DECODE_SEI=1025, - DE265_WARNING_COLLOCATED_MOTION_VECTOR_OUTSIDE_IMAGE_AREA=1026 -} de265_error; - +/* === error code management === */ LIBDE265_API const char* de265_get_error_text(de265_error err); /* Returns true, if 'err' is DE265_OK or a warning. @@ -387,6 +329,20 @@ enum de265_param { //DE265_DECODER_PARAM_DISABLE_INTRA_RESIDUAL_IDCT=10 // (bool) disable decoding of IDCT residuals in MC blocks }; +/* --- callback --- */ +struct de265_callback_block +{ + void (*get_vps)(video_parameter_set* vps); + void (*get_sps)(seq_parameter_set* sps); + void (*get_pps)(pic_parameter_set* pps); + void (*get_image)(de265_image* img); +}; +LIBDE265_API void de265_callback_register(de265_decoder_context*, de265_callback_block*); +LIBDE265_API void de265_callback_unregister(de265_decoder_context*); + +/* The user data pointer will be given to the get_buffer() and release_buffer() functions + in de265_image_allocation. */ + // sorted such that a large ID includes all optimizations from lower IDs enum de265_acceleration { de265_acceleration_SCALAR = 0, // only fallback implementation @@ -430,8 +386,5 @@ LIBDE265_API de265_error de265_init(void); LIBDE265_API de265_error de265_free(void); -#ifdef __cplusplus -} -#endif #endif diff --git a/libde265/decctx.cc b/libde265/decctx.cc index edebb7136..ad061c7fd 100644 --- a/libde265/decctx.cc +++ b/libde265/decctx.cc @@ -301,6 +301,7 @@ decoder_context::decoder_context() */ + cbb = NULL; // --- internal data --- @@ -540,6 +541,10 @@ de265_error decoder_context::read_vps_NAL(bitreader& reader) new_vps->dump(param_vps_headers_fd); } + if (cbb != NULL && cbb->get_vps != NULL) { + cbb->get_vps(new_vps.get()); + } + vps[ new_vps->video_parameter_set_id ] = new_vps; return DE265_OK; @@ -560,6 +565,10 @@ de265_error decoder_context::read_sps_NAL(bitreader& reader) new_sps->dump(param_sps_headers_fd); } + if (cbb != NULL && cbb->get_sps != NULL) { + cbb->get_sps(new_sps.get()); + } + sps[ new_sps->seq_parameter_set_id ] = new_sps; return DE265_OK; @@ -577,6 +586,10 @@ de265_error decoder_context::read_pps_NAL(bitreader& reader) new_pps->dump(param_pps_headers_fd); } + if (cbb != NULL && cbb->get_pps != NULL) { + cbb->get_pps(new_pps.get()); + } + if (success) { pps[ (int)new_pps->pic_parameter_set_id ] = new_pps; } @@ -596,6 +609,7 @@ de265_error decoder_context::read_sei_NAL(bitreader& reader, bool suffix) if ((err=read_sei(&reader,&sei, suffix, current_sps.get())) == DE265_OK) { dump_sei(&sei, current_sps.get()); + // TODO: add SEI callback here if (image_units.empty()==false && suffix) { image_units.back()->suffix_SEIs.push_back(sei); @@ -635,6 +649,7 @@ de265_error decoder_context::read_slice_NAL(bitreader& reader, NAL_unit* nal, na shdr->dump_slice_segment_header(this, param_slice_headers_fd); } + // TODO: add slice_header callback here if (process_slice_segment_header(shdr, &err, nal->pts, &nal_hdr, nal->user_data) == false) { @@ -778,6 +793,9 @@ de265_error decoder_context::decode_some(bool* did_work) break; } + if (cbb != NULL && cbb->get_image != NULL) { + cbb->get_image(imgunit->img); + } push_picture_to_output_queue(imgunit); @@ -2228,6 +2246,18 @@ void decoder_context::calc_tid_and_framerate_ratio() } +void decoder_context::callback_register(de265_callback_block* cbb_) +{ + cbb = cbb_; +} + + +void decoder_context::callback_unregister() +{ + cbb = NULL; +} + + void error_queue::add_warning(de265_error warning, bool once) { // check if warning was already shown diff --git a/libde265/decctx.h b/libde265/decctx.h index c1acdcef0..e40b28816 100644 --- a/libde265/decctx.h +++ b/libde265/decctx.h @@ -412,6 +412,11 @@ class decoder_context : public base_context { int change_framerate(int more_vs_less); // 1: more, -1: less void set_framerate_ratio(int percent); + // --- decode callback --- + + void callback_register(de265_callback_block* cbb); + void callback_unregister(); + private: // input parameters int limit_HighestTid; // never switch to a layer above this one @@ -429,6 +434,8 @@ class decoder_context : public base_context { } framedrop_tab[100+1]; int framedrop_tid_index[6+1]; + de265_callback_block* cbb; + void compute_framedrop_table(); void calc_tid_and_framerate_ratio(); diff --git a/libde265/en265.h b/libde265/en265.h index a22e5d14a..9c53c3d49 100644 --- a/libde265/en265.h +++ b/libde265/en265.h @@ -23,10 +23,6 @@ #ifndef EN265_H #define EN265_H -#ifdef __cplusplus -extern "C" { -#endif - #include @@ -210,9 +206,5 @@ LIBDE265_API void en265_free_packet(en265_encoder_context*, struct en265_packet* LIBDE265_API int en265_number_of_queued_packets(en265_encoder_context*); -#ifdef __cplusplus -} -#endif - #endif diff --git a/libde265/sps.h b/libde265/sps.h index b06151d23..e48796def 100644 --- a/libde265/sps.h +++ b/libde265/sps.h @@ -25,7 +25,7 @@ #include "libde265/vui.h" #include "libde265/bitstream.h" #include "libde265/refpic.h" -#include "libde265/de265.h" +#include "libde265/de265-error.h" #include "libde265/cabac.h" #include diff --git a/libde265/vps.h b/libde265/vps.h index 04c9c1529..08d7d8d07 100644 --- a/libde265/vps.h +++ b/libde265/vps.h @@ -30,7 +30,7 @@ #endif #include "libde265/bitstream.h" -#include "libde265/de265.h" +#include "libde265/de265-error.h" #include "libde265/cabac.h" #include diff --git a/libde265/vui.h b/libde265/vui.h index c412669ae..e281bbf32 100644 --- a/libde265/vui.h +++ b/libde265/vui.h @@ -21,7 +21,7 @@ #ifndef DE265_VUI_H #define DE265_VUI_H -#include "libde265/de265.h" +#include "libde265/de265-error.h" #include "libde265/bitstream.h" #include