├── .MODULE_LICENSE_BSD ├── .MODULE_NAME_libvideo-decode ├── .clang-format ├── COPYING ├── README.md ├── atom.mk ├── config.in ├── core ├── include │ └── video-decode │ │ ├── vdec_core.h │ │ └── vdec_internal.h └── src │ ├── vdec_core_priv.h │ ├── vdec_dbg.c │ ├── vdec_enums.c │ ├── vdec_format.c │ ├── vdec_h264.c │ └── vdec_h265.c ├── ffmpeg ├── include │ └── video-decode │ │ └── vdec_ffmpeg.h └── src │ ├── vdec_ffmpeg.c │ └── vdec_ffmpeg_priv.h ├── include └── video-decode │ └── vdec.h ├── mediacodec ├── include │ └── video-decode │ │ └── vdec_mediacodec.h └── src │ ├── vdec_mediacodec.c │ ├── vdec_mediacodec_convert.h │ └── vdec_mediacodec_priv.h ├── src ├── vdec.c └── vdec_priv.h ├── tools └── vdec.c ├── turbojpeg ├── include │ └── video-decode │ │ └── vdec_turbojpeg.h └── src │ ├── vdec_turbojpeg.c │ └── vdec_turbojpeg_priv.h └── videotoolbox ├── include └── video-decode │ └── vdec_videotoolbox.h └── src ├── vdec_videotoolbox.c └── vdec_videotoolbox_priv.h /.MODULE_LICENSE_BSD: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Parrot Drones SAS -------------------------------------------------------------------------------- /.MODULE_NAME_libvideo-decode: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parrot-Developers/libvideo-decode/b9ad39addbcbff439bdd5cb7a40969060e3e3490/.MODULE_NAME_libvideo-decode -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -8 4 | AlignAfterOpenBracket: true 5 | AlignEscapedNewlinesLeft: false 6 | AlignOperands: true 7 | AlignTrailingComments: false 8 | AllowAllParametersOfDeclarationOnNextLine: false 9 | AllowShortFunctionsOnASingleLine: Empty 10 | AllowShortIfStatementsOnASingleLine: false 11 | AllowShortLoopsOnASingleLine: false 12 | AlwaysBreakBeforeMultilineStrings: true 13 | BinPackArguments: false 14 | BinPackParameters: false 15 | BreakBeforeBinaryOperators: None 16 | BreakBeforeBraces: WebKit 17 | BreakConstructorInitializers: AfterColon 18 | BreakStringLiterals: false 19 | ContinuationIndentWidth: 8 20 | ConstructorInitializerIndentWidth: 16 21 | IndentCaseLabels: false 22 | IndentPPDirectives: AfterHash 23 | IndentWidth: 8 24 | Language: Cpp 25 | MaxEmptyLinesToKeep: 2 26 | SortIncludes: true 27 | SpaceAfterCStyleCast: false 28 | UseTab: Always 29 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Parrot Drones SAS 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | * Redistributions of source code must retain the above copyright 6 | notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright 8 | notice, this list of conditions and the following disclaimer in the 9 | documentation and/or other materials provided with the distribution. 10 | * Neither the name of the Parrot Drones SAS Company nor the 11 | names of its contributors may be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libvideo-decode - Video decoding library 2 | 3 | _libvideo-decode_ is a C library that provides a common API for decoding 4 | H.264, H.265 video and JPEG photos across various platforms. 5 | 6 | The library uses hardware-accelerated decoding when available. 7 | 8 | ## Implementations 9 | 10 | The following implementations are available: 11 | 12 | * FFmpeg (CPU or CUSA acceleration on Nvidia GPU if available) 13 | * MediaCodec on Android 4.2+ (through the NDK API on Android 5.0+ 14 | or the Java API through JNI) 15 | * TurboJPEG using libjpeg-turbo 16 | * VideoToolbox on iOS 8+ and MacOS X 17 | 18 | The application can force using a specific implementation or let the library 19 | decide according to what is supported by the platform. 20 | 21 | ## Dependencies 22 | 23 | The library depends on the following Alchemy modules: 24 | 25 | * libfutils 26 | * libh264 27 | * libh265 28 | * libmedia-buffers 29 | * libmedia-buffers-memory 30 | * libmedia-buffers-memory-generic 31 | * libpomp 32 | * libulog 33 | * libvideo-decode-core 34 | * libvideo-defs 35 | * libvideo-metadata 36 | * (optional) ffmpeg-libav (for FFmpeg support) 37 | * (optional) libjpeg-turbo (for TurboJPEG support) 38 | * (optional) libyuv (for TurboJPEG support) 39 | 40 | The library also depends on the following frameworks for iOS and MacOS only: 41 | 42 | * Foundation 43 | * CoreMedia 44 | * CoreVideo 45 | * VideoToolbox 46 | 47 | ## Building 48 | 49 | Building is activated by enabling _libvideo-decode_ in the Alchemy build 50 | configuration. 51 | 52 | ## Operation 53 | 54 | Operations are asynchronous: the application pushes buffers to decode in the 55 | input queue and is notified of decoded frames through a callback function. 56 | 57 | Some decoders need the input buffers to be originating from its own buffer 58 | pool; when the input buffer pool returned by the library is not _NULL_ it must 59 | be used and input buffers cannot be shared with other video pipeline elements. 60 | 61 | ### Threading model 62 | 63 | The library is designed to run on a _libpomp_ event loop (_pomp_loop_, see 64 | _libpomp_ documentation). All API functions must be called from the _pomp_loop_ 65 | thread. All callback functions (frame_output, flush or stop) are called from 66 | the _pomp_loop_ thread. 67 | 68 | ## Testing 69 | 70 | The library can be tested using the provided _vdec_ command-line tool which 71 | takes as input a raw H.264 or H.265 (Annex B byte stream) file and can 72 | optionally output a decoded YUV file. It also supports decoding JPEG images. 73 | 74 | To build the tool, enable _vdec_ in the Alchemy build configuration. 75 | 76 | For a list of available options, run 77 | 78 | $ vdec -h 79 | -------------------------------------------------------------------------------- /atom.mk: -------------------------------------------------------------------------------- 1 | 2 | LOCAL_PATH := $(call my-dir) 3 | 4 | # API library. This is the library that most programs should use. 5 | include $(CLEAR_VARS) 6 | LOCAL_MODULE := libvideo-decode 7 | LOCAL_CATEGORY_PATH := libs 8 | LOCAL_DESCRIPTION := Video decoding library 9 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include 10 | LOCAL_CFLAGS := -DVDEC_API_EXPORTS -fvisibility=hidden -std=gnu99 -D_GNU_SOURCE 11 | LOCAL_SRC_FILES := \ 12 | src/vdec.c 13 | LOCAL_LIBRARIES := \ 14 | libh264 \ 15 | libh265 \ 16 | libpomp \ 17 | libulog \ 18 | libvideo-decode-core \ 19 | libvideo-defs 20 | LOCAL_CONFIG_FILES := config.in 21 | $(call load-config) 22 | LOCAL_CONDITIONAL_LIBRARIES := \ 23 | CONFIG_VDEC_AML:libvideo-decode-aml \ 24 | CONFIG_VDEC_FFMPEG:libvideo-decode-ffmpeg \ 25 | CONFIG_VDEC_HISI:libvideo-decode-hisi \ 26 | CONFIG_VDEC_MEDIACODEC:libvideo-decode-mediacodec \ 27 | CONFIG_VDEC_QCOM:libvideo-decode-qcom \ 28 | CONFIG_VDEC_TURBOJPEG:libvideo-decode-turbojpeg \ 29 | CONFIG_VDEC_VIDEOTOOLBOX:libvideo-decode-videotoolbox 30 | LOCAL_EXPORT_LDLIBS := -lvideo-decode-core 31 | ifeq ("$(TARGET_OS)","windows") 32 | LOCAL_LDLIBS += -lws2_32 33 | endif 34 | 35 | include $(BUILD_LIBRARY) 36 | 37 | include $(CLEAR_VARS) 38 | 39 | # Core library, common code for all implementations and structures definitions. 40 | # Used by implementations. 41 | LOCAL_MODULE := libvideo-decode-core 42 | LOCAL_CATEGORY_PATH := libs 43 | LOCAL_DESCRIPTION := Video decoding library: core files 44 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/core/include 45 | LOCAL_CFLAGS := -DVDEC_API_EXPORTS -fvisibility=hidden -std=gnu99 -D_GNU_SOURCE 46 | LOCAL_SRC_FILES := \ 47 | core/src/vdec_dbg.c \ 48 | core/src/vdec_enums.c \ 49 | core/src/vdec_format.c \ 50 | core/src/vdec_h264.c \ 51 | core/src/vdec_h265.c 52 | LOCAL_LIBRARIES := \ 53 | libfutils \ 54 | libh264 \ 55 | libh265 \ 56 | libmedia-buffers \ 57 | libmedia-buffers-memory \ 58 | libulog \ 59 | libvideo-defs \ 60 | libvideo-metadata 61 | ifeq ("$(TARGET_OS)","windows") 62 | LOCAL_LDLIBS += -lws2_32 63 | endif 64 | 65 | include $(BUILD_LIBRARY) 66 | 67 | 68 | include $(CLEAR_VARS) 69 | 70 | # ffmpeg implementation. can be enabled in the product configuration 71 | LOCAL_MODULE := libvideo-decode-ffmpeg 72 | LOCAL_CATEGORY_PATH := libs 73 | LOCAL_DESCRIPTION := Video decoding library: ffmpeg implementation 74 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/include 75 | LOCAL_CFLAGS := -DVDEC_API_EXPORTS -fvisibility=hidden -std=gnu99 -D_GNU_SOURCE 76 | LOCAL_SRC_FILES := \ 77 | ffmpeg/src/vdec_ffmpeg.c 78 | LOCAL_LIBRARIES := \ 79 | ffmpeg-libav \ 80 | libfutils \ 81 | libmedia-buffers \ 82 | libmedia-buffers-memory \ 83 | libmedia-buffers-memory-generic \ 84 | libpomp \ 85 | libulog \ 86 | libvideo-decode-core \ 87 | libvideo-defs \ 88 | libvideo-metadata 89 | ifeq ("$(TARGET_OS)","windows") 90 | LOCAL_LDLIBS += -lws2_32 91 | endif 92 | 93 | include $(BUILD_LIBRARY) 94 | 95 | ifeq ("$(TARGET_OS)-$(TARGET_OS_FLAVOUR)","linux-android") 96 | 97 | include $(CLEAR_VARS) 98 | 99 | # MediaCodec (Android) implementation. 100 | # can be enabled in the product configuration 101 | LOCAL_MODULE := libvideo-decode-mediacodec 102 | LOCAL_CATEGORY_PATH := libs 103 | LOCAL_DESCRIPTION := Video decoding library: mediacodec implementation 104 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/mediacodec/include 105 | LOCAL_CFLAGS := -DVDEC_API_EXPORTS -fvisibility=hidden -std=gnu99 106 | LOCAL_LDLIBS := -lmediandk 107 | LOCAL_SRC_FILES := \ 108 | mediacodec/src/vdec_mediacodec.c 109 | LOCAL_LIBRARIES := \ 110 | libfutils \ 111 | libh264 \ 112 | libh265 \ 113 | libmedia-buffers \ 114 | libmedia-buffers-memory \ 115 | libmedia-buffers-memory-generic \ 116 | libpomp \ 117 | libulog \ 118 | libvideo-decode-core \ 119 | libvideo-defs \ 120 | libvideo-metadata 121 | 122 | include $(BUILD_LIBRARY) 123 | 124 | endif 125 | 126 | include $(CLEAR_VARS) 127 | 128 | # turbojpeg implementation. can be enabled in the product configuration. 129 | LOCAL_MODULE := libvideo-decode-turbojpeg 130 | LOCAL_CATEGORY_PATH := libs 131 | LOCAL_DESCRIPTION := Video decoding library: turbojpeg implementation 132 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/turbojpeg/include 133 | LOCAL_CFLAGS := -DVDEC_API_EXPORTS -fvisibility=hidden -std=gnu99 -D_GNU_SOURCE 134 | LOCAL_SRC_FILES := \ 135 | turbojpeg/src/vdec_turbojpeg.c 136 | LOCAL_LIBRARIES := \ 137 | libfutils \ 138 | libjpeg-turbo \ 139 | libmedia-buffers \ 140 | libmedia-buffers-memory \ 141 | libmedia-buffers-memory-generic \ 142 | libpomp \ 143 | libulog \ 144 | libvideo-decode-core \ 145 | libvideo-defs \ 146 | libvideo-metadata \ 147 | libyuv 148 | 149 | include $(BUILD_LIBRARY) 150 | 151 | 152 | ifeq ("${TARGET_OS}", "darwin") 153 | include $(CLEAR_VARS) 154 | 155 | # VideoToolbox (iOS/macOS) implementation. 156 | # can be enabled in the product configuration 157 | LOCAL_MODULE := libvideo-decode-videotoolbox 158 | LOCAL_CATEGORY_PATH := libs 159 | LOCAL_DESCRIPTION := Video decoding library: videotoolbox implementation 160 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/videotoolbox/include 161 | LOCAL_CFLAGS := -DVDEC_API_EXPORTS -fvisibility=hidden -std=gnu99 162 | LOCAL_SRC_FILES := \ 163 | videotoolbox/src/vdec_videotoolbox.c 164 | LOCAL_LIBRARIES := \ 165 | libfutils \ 166 | libmedia-buffers \ 167 | libmedia-buffers-memory \ 168 | libmedia-buffers-memory-generic \ 169 | libpomp \ 170 | libulog \ 171 | libvideo-decode-core \ 172 | libvideo-defs \ 173 | libvideo-metadata 174 | LOCAL_LDLIBS += \ 175 | -framework Foundation \ 176 | -framework CoreMedia \ 177 | -framework CoreVideo \ 178 | -framework VideoToolbox 179 | 180 | include $(BUILD_LIBRARY) 181 | endif 182 | 183 | 184 | include $(CLEAR_VARS) 185 | 186 | LOCAL_MODULE := vdec 187 | LOCAL_DESCRIPTION := Video decoding program 188 | LOCAL_CATEGORY_PATH := multimedia 189 | LOCAL_SRC_FILES := tools/vdec.c 190 | LOCAL_LIBRARIES := \ 191 | libfutils \ 192 | libh264 \ 193 | libh265 \ 194 | libmedia-buffers \ 195 | libmedia-buffers-memory \ 196 | libmedia-buffers-memory-generic \ 197 | libphoto-metadata \ 198 | libpomp \ 199 | libulog \ 200 | libvideo-decode \ 201 | libvideo-defs \ 202 | libvideo-raw 203 | 204 | ifeq ("$(TARGET_OS)-$(TARGET_OS_FLAVOUR)-$(TARGET_PRODUCT_VARIANT)","linux-generic-raspi") 205 | LOCAL_LDLIBS += -lbcm_host -lvchiq_arm 206 | else ifeq ("$(TARGET_OS)","windows") 207 | LOCAL_LDLIBS += -lws2_32 208 | endif 209 | 210 | 211 | include $(BUILD_EXECUTABLE) 212 | -------------------------------------------------------------------------------- /config.in: -------------------------------------------------------------------------------- 1 | config VDEC_FFMPEG 2 | bool "vdec ffmpeg implementation" 3 | default false 4 | help 5 | Enable the ffmpeg implementation in libvideo-decode. 6 | 7 | config VDEC_MEDIACODEC 8 | bool "vdec mediacodec implementation" 9 | default false 10 | help 11 | Enable the MediaCodec (Android) implementation in libvideo-decode. 12 | 13 | config VDEC_TURBOJPEG 14 | bool "vdec turbojpeg implementation" 15 | default false 16 | help 17 | Enable the TurboJPEG implementation in libvideo-decode. 18 | 19 | config VDEC_VIDEOTOOLBOX 20 | bool "vdec videotoolbox implementation" 21 | default false 22 | help 23 | Enable the VideoToolbox (iOS/macos) implementation in libvideo-decode. 24 | 25 | config VDEC_HISI 26 | bool "vdec hisi implementation" 27 | default false 28 | help 29 | Enable the HiSilicon implementation in libvideo-decode. 30 | 31 | config VDEC_AML 32 | bool "vdec aml implementation" 33 | default false 34 | help 35 | Enable the Amlogic implementation in libvideo-decode. 36 | 37 | config VDEC_QCOM 38 | bool "vdec qcom implementation" 39 | default false 40 | help 41 | Enable the Qualcomm implementation in libvideo-decode. 42 | -------------------------------------------------------------------------------- /core/include/video-decode/vdec_core.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_CORE_H_ 28 | #define _VDEC_CORE_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif /* __cplusplus */ 40 | 41 | /* To be used for all public API */ 42 | #ifdef VDEC_API_EXPORTS 43 | # ifdef _WIN32 44 | # define VDEC_API __declspec(dllexport) 45 | # else /* !_WIN32 */ 46 | # define VDEC_API __attribute__((visibility("default"))) 47 | # endif /* !_WIN32 */ 48 | #else /* !VDEC_API_EXPORTS */ 49 | # define VDEC_API 50 | #endif /* !VDEC_API_EXPORTS */ 51 | 52 | 53 | /** 54 | * mbuf ancillary data key for the input timestamp. 55 | * 56 | * Content is a 64bits microseconds value on a monotonic clock 57 | */ 58 | #define VDEC_ANCILLARY_KEY_INPUT_TIME "vdec.input_time" 59 | 60 | /** 61 | * mbuf ancillary data key for the dequeue timestamp. 62 | * 63 | * Content is a 64bits microseconds value on a monotonic clock 64 | */ 65 | #define VDEC_ANCILLARY_KEY_DEQUEUE_TIME "vdec.dequeue_time" 66 | 67 | /** 68 | * mbuf ancillary data key for the output timestamp. 69 | * 70 | * Content is a 64bits microseconds value on a monotonic clock 71 | */ 72 | #define VDEC_ANCILLARY_KEY_OUTPUT_TIME "vdec.output_time" 73 | 74 | 75 | /* Debug files flags. Can be set in configuration as well as in 76 | * VDEC_DBG_FLAGS environment variables (with VDEC_DBG_DIR specifying the 77 | * output directory. */ 78 | 79 | /* Input bitstream */ 80 | #define VDEC_DBG_FLAG_INPUT_BITSTREAM (1 << 0) 81 | 82 | /* Output YUV */ 83 | #define VDEC_DBG_FLAG_OUTPUT_YUV (1 << 1) 84 | 85 | /* H.264 parsing and analysis */ 86 | #define VDEC_DBG_FLAG_ANALYSIS (1 << 2) 87 | 88 | 89 | /* Forward declarations */ 90 | struct vdec_decoder; 91 | 92 | 93 | /* Supported decoder implementations */ 94 | enum vdec_decoder_implem { 95 | /* Automatically select decoder */ 96 | VDEC_DECODER_IMPLEM_AUTO = 0, 97 | 98 | /* FFmpeg decoder implementation */ 99 | VDEC_DECODER_IMPLEM_FFMPEG, 100 | 101 | /* Android MediaCodec decoder implementation */ 102 | VDEC_DECODER_IMPLEM_MEDIACODEC, 103 | 104 | /* Apple VideoToolbox decoder implementation */ 105 | VDEC_DECODER_IMPLEM_VIDEOTOOLBOX, 106 | 107 | /* HiSilicon decoder implementation */ 108 | VDEC_DECODER_IMPLEM_HISI, 109 | 110 | /* Amlogic decoder implementation */ 111 | VDEC_DECODER_IMPLEM_AML, 112 | 113 | /* TurboJPEG decoder implementation */ 114 | VDEC_DECODER_IMPLEM_TURBOJPEG, 115 | 116 | /* Qualcomm decoder implementation */ 117 | VDEC_DECODER_IMPLEM_QCOM, 118 | 119 | /* End of supported implementation */ 120 | VDEC_DECODER_IMPLEM_MAX, 121 | }; 122 | 123 | 124 | /* Decoder initial configuration, implementation specific extension 125 | * Each implementation might provide implementation specific configuration with 126 | * a structure compatible with this base structure (i.e. which starts with the 127 | * same implem field). */ 128 | struct vdec_config_impl { 129 | /* Decoder implementation for this extension */ 130 | enum vdec_decoder_implem implem; 131 | }; 132 | 133 | 134 | /* Decoder initial configuration */ 135 | struct vdec_config { 136 | /* Decoder instance name (optional, can be null, copied internally) */ 137 | const char *name; 138 | 139 | /* Decoder implementation (AUTO means no preference, 140 | * use the default implementation for the platform) */ 141 | enum vdec_decoder_implem implem; 142 | 143 | /* Encoding type */ 144 | enum vdef_encoding encoding; 145 | 146 | /* Input buffer pool preferred minimum buffer count, used 147 | * only if the implementation uses its own input buffer pool 148 | * (0 means no preference, use the default value) */ 149 | unsigned int preferred_min_in_buf_count; 150 | 151 | /* Output buffer pool preferred minimum buffer count 152 | * (0 means no preference, use the default value) */ 153 | unsigned int preferred_min_out_buf_count; 154 | 155 | /* Preferred decoding thread count (0 means no preference, 156 | * use the default value; 1 means no multi-threading; 157 | * only relevant for CPU decoding implementations); 158 | * can be overriden by the VDEC_PREFERRED_THREAD_COUNT 159 | * environment variable */ 160 | unsigned int preferred_thread_count; 161 | 162 | /* Favor low delay decoding (e.g. for a live stream); 163 | * can be overriden by the VDEC_LOW_DELAY environment variable */ 164 | int low_delay; 165 | 166 | /* Generate an H.264 grey IDR frame for synchronization if needed */ 167 | int gen_grey_idr; 168 | 169 | /* Output silent frames */ 170 | int output_silent_frames; 171 | 172 | /* Preferred output buffers data format (optional, 0 means any) */ 173 | struct vdef_raw_format preferred_output_format; 174 | 175 | /* Debug output directory */ 176 | const char *dbg_dir; 177 | 178 | /* Debug flags */ 179 | uint32_t dbg_flags; 180 | 181 | /* Implementation specific extensions (optional, can be NULL) 182 | * If not null, implem_cfg must match the following requirements: 183 | * - this->implem_cfg->implem == this->implem 184 | * - this->implem != VDEC_DECODER_IMPLEM_AUTO 185 | * - The real type of implem_cfg must be the implementation specific 186 | * structure, not struct vdec_config_impl */ 187 | struct vdec_config_impl *implem_cfg; 188 | }; 189 | 190 | 191 | /* Decoder callback functions */ 192 | struct vdec_cbs { 193 | /* Frame output callback function (mandatory). 194 | * The library retains ownership of the output frame and the 195 | * application must reference it if needed after returning from the 196 | * callback function. The status is 0 in case of success, a negative 197 | * errno otherwise. In case of error no frame is output and frame 198 | * is NULL. An error -EBADMSG means a resync is required (IDR frame). 199 | * @param dec: decoder instance handle 200 | * @param status: frame output status 201 | * @param frame: output frame 202 | * @param userdata: user data pointer */ 203 | void (*frame_output)(struct vdec_decoder *dec, 204 | int status, 205 | struct mbuf_raw_video_frame *frame, 206 | void *userdata); 207 | 208 | /* Flush callback function, called when flushing is complete (optional). 209 | * @param dec: decoder instance handle 210 | * @param userdata: user data pointer */ 211 | void (*flush)(struct vdec_decoder *dec, void *userdata); 212 | 213 | /* Stop callback function, called when stopping is complete (optional). 214 | * @param dec: decoder instance handle 215 | * @param userdata: user data pointer */ 216 | void (*stop)(struct vdec_decoder *dec, void *userdata); 217 | }; 218 | 219 | 220 | /** 221 | * ToString function for enum vdec_decoder_implem. 222 | * @param implem: implementation value to convert 223 | * @return a string description of the implementation 224 | */ 225 | VDEC_API const char *vdec_decoder_implem_str(enum vdec_decoder_implem implem); 226 | 227 | 228 | #ifdef __cplusplus 229 | } 230 | #endif /* __cplusplus */ 231 | 232 | #endif /* !_VDEC_CORE_H_ */ 233 | -------------------------------------------------------------------------------- /core/include/video-decode/vdec_internal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_INTERNAL_H_ 28 | #define _VDEC_INTERNAL_H_ 29 | 30 | #ifdef __cplusplus 31 | # include 32 | /* codecheck_ignore[SPACING] */ 33 | using std::atomic_uint; 34 | #else 35 | # include 36 | #endif 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif /* __cplusplus */ 46 | 47 | /* To be used for all public API */ 48 | #ifdef VDEC_API_EXPORTS 49 | # ifdef _WIN32 50 | # define VDEC_INTERNAL_API __declspec(dllexport) 51 | # else /* !_WIN32 */ 52 | # define VDEC_INTERNAL_API __attribute__((visibility("default"))) 53 | # endif /* !_WIN32 */ 54 | #else /* !VDEC_API_EXPORTS */ 55 | # define VDEC_INTERNAL_API 56 | #endif /* !VDEC_API_EXPORTS */ 57 | 58 | 59 | /* Specific logging functions : log the instance ID before the log message */ 60 | #define VDEC_LOG_INT(_pri, _fmt, ...) \ 61 | do { \ 62 | char *prefix = (self != NULL && self->base != NULL) \ 63 | ? self->base->dec_name \ 64 | : ""; \ 65 | ULOG_PRI(_pri, \ 66 | "%s%s" _fmt, \ 67 | prefix != NULL ? prefix : "", \ 68 | prefix != NULL ? ": " : "", \ 69 | ##__VA_ARGS__); \ 70 | } while (0) 71 | #define VDEC_LOGD(_fmt, ...) VDEC_LOG_INT(ULOG_DEBUG, _fmt, ##__VA_ARGS__) 72 | #define VDEC_LOGI(_fmt, ...) VDEC_LOG_INT(ULOG_INFO, _fmt, ##__VA_ARGS__) 73 | #define VDEC_LOGW(_fmt, ...) VDEC_LOG_INT(ULOG_WARN, _fmt, ##__VA_ARGS__) 74 | #define VDEC_LOGE(_fmt, ...) VDEC_LOG_INT(ULOG_ERR, _fmt, ##__VA_ARGS__) 75 | #define VDEC_LOG_ERRNO(_fmt, _err, ...) \ 76 | do { \ 77 | char *prefix = (self != NULL && self->base != NULL) \ 78 | ? self->base->dec_name \ 79 | : ""; \ 80 | ULOGE_ERRNO((_err), \ 81 | "%s%s" _fmt, \ 82 | prefix != NULL ? prefix : "", \ 83 | prefix != NULL ? ": " : "", \ 84 | ##__VA_ARGS__); \ 85 | } while (0) 86 | #define VDEC_LOGW_ERRNO(_fmt, _err, ...) \ 87 | do { \ 88 | char *prefix = (self != NULL && self->base != NULL) \ 89 | ? self->base->dec_name \ 90 | : ""; \ 91 | ULOGW_ERRNO((_err), \ 92 | "%s%s" _fmt, \ 93 | prefix != NULL ? prefix : "", \ 94 | prefix != NULL ? ": " : "", \ 95 | ##__VA_ARGS__); \ 96 | } while (0) 97 | #define VDEC_LOG_ERRNO_RETURN_IF(_cond, _err) \ 98 | do { \ 99 | if (ULOG_UNLIKELY(_cond)) { \ 100 | VDEC_LOG_ERRNO("", (_err)); \ 101 | return; \ 102 | } \ 103 | } while (0) 104 | #define VDEC_LOG_ERRNO_RETURN_ERR_IF(_cond, _err) \ 105 | do { \ 106 | if (ULOG_UNLIKELY(_cond)) { \ 107 | int __pdraw_errno__err = (_err); \ 108 | VDEC_LOG_ERRNO("", (__pdraw_errno__err)); \ 109 | return -(__pdraw_errno__err); \ 110 | } \ 111 | } while (0) 112 | #define VDEC_LOG_ERRNO_RETURN_VAL_IF(_cond, _err, _val) \ 113 | do { \ 114 | if (ULOG_UNLIKELY(_cond)) { \ 115 | VDEC_LOG_ERRNO("", (_err)); \ 116 | /* codecheck_ignore[RETURN_PARENTHESES] */ \ 117 | return (_val); \ 118 | } \ 119 | } while (0) 120 | 121 | 122 | struct vdec_ops { 123 | int (*get_supported_input_formats)( 124 | const struct vdef_coded_format **formats); 125 | 126 | int (*create)(struct vdec_decoder *base); 127 | 128 | int (*flush)(struct vdec_decoder *base, int discard); 129 | 130 | int (*stop)(struct vdec_decoder *base); 131 | 132 | int (*destroy)(struct vdec_decoder *base); 133 | 134 | int (*set_jpeg_params)(struct vdec_decoder *base); 135 | 136 | int (*set_h264_ps)(struct vdec_decoder *base, 137 | const uint8_t *sps, 138 | size_t sps_size, 139 | const uint8_t *pps, 140 | size_t pps_size, 141 | const struct vdef_coded_format *format); 142 | 143 | int (*set_h265_ps)(struct vdec_decoder *base, 144 | const uint8_t *vps, 145 | size_t vps_size, 146 | const uint8_t *sps, 147 | size_t sps_size, 148 | const uint8_t *pps, 149 | size_t pps_size, 150 | const struct vdef_coded_format *format); 151 | 152 | struct mbuf_pool *(*get_input_buffer_pool)(struct vdec_decoder *base); 153 | 154 | struct mbuf_coded_video_frame_queue *(*get_input_buffer_queue)( 155 | struct vdec_decoder *base); 156 | }; 157 | 158 | 159 | struct video_info { 160 | /* Picture resolution in pixels */ 161 | struct vdef_dim resolution; 162 | 163 | uint8_t bit_depth; 164 | 165 | /* Source aspect ratio size (1 if unknown) */ 166 | struct vdef_dim sar; 167 | 168 | /* Crop rectangle in pixels */ 169 | struct vdef_rect crop; 170 | 171 | /* Full range flag */ 172 | int full_range; 173 | 174 | /* Color primaries */ 175 | enum vdef_color_primaries color_primaries; 176 | 177 | /* Transfer function */ 178 | enum vdef_transfer_function transfer_function; 179 | 180 | /* Matrix coefficients */ 181 | enum vdef_matrix_coefs matrix_coefs; 182 | 183 | /* Declared framerate from time_scale and num_units_in_tick 184 | * (0 if unknown) */ 185 | struct vdef_frac framerate; 186 | 187 | /* NAL HRD bitrate (0 if unknown) */ 188 | uint32_t nal_hrd_bitrate; 189 | 190 | /* NAL HRD CPB size (0 if unknown) */ 191 | uint32_t nal_hrd_cpb_size; 192 | 193 | /* VCL HRD bitrate (0 if unknown) */ 194 | uint32_t vcl_hrd_bitrate; 195 | 196 | /* VCL HRD CPB size (0 if unknown) */ 197 | uint32_t vcl_hrd_cpb_size; 198 | }; 199 | 200 | 201 | struct vdec_decoder { 202 | /* Reserved */ 203 | struct vdec_decoder *base; 204 | void *derived; 205 | const struct vdec_ops *ops; 206 | struct pomp_loop *loop; 207 | struct vdec_cbs cbs; 208 | void *userdata; 209 | struct vdec_config config; 210 | int configured; 211 | struct video_info video_info; 212 | 213 | int dec_id; 214 | char *dec_name; 215 | 216 | union { 217 | struct h264_reader *h264; 218 | struct h265_reader *h265; 219 | } reader; 220 | struct { 221 | char *dir; 222 | unsigned int frame_index; 223 | FILE *input_bs; 224 | FILE *output_yuv; 225 | FILE *analysis; 226 | } dbg; 227 | atomic_uint_least64_t last_timestamp; 228 | 229 | struct { 230 | /* Frames that have passed the input filter */ 231 | atomic_uint in; 232 | /* Frames that have been pushed to the decoder */ 233 | atomic_uint pushed; 234 | /* Frames that have been pulled from the decoder */ 235 | atomic_uint pulled; 236 | /* Frames that have been output (frame_output) */ 237 | atomic_uint out; 238 | } counters; 239 | }; 240 | 241 | 242 | VDEC_INTERNAL_API int 243 | vdec_format_convert(struct mbuf_coded_video_frame *frame, 244 | const struct vdef_coded_format *target_format); 245 | 246 | 247 | VDEC_INTERNAL_API bool vdec_is_sync_frame(struct mbuf_coded_video_frame *frame, 248 | struct vdef_coded_frame *info); 249 | 250 | 251 | VDEC_INTERNAL_API void 252 | vdec_call_frame_output_cb(struct vdec_decoder *base, 253 | int status, 254 | struct mbuf_raw_video_frame *frame); 255 | 256 | 257 | VDEC_INTERNAL_API void vdec_call_flush_cb(struct vdec_decoder *base); 258 | 259 | 260 | VDEC_INTERNAL_API void vdec_call_stop_cb(struct vdec_decoder *base); 261 | 262 | 263 | /** 264 | * Default filter for the input frame queue. 265 | * This function is intended to be used as a standalone input filter. 266 | * It will call vdec_default_input_filter_internal(), and then 267 | * vdec_default_input_filter_internal_confirm_frame() if the former returned 268 | * true. 269 | * 270 | * @param frame: The frame to filter. 271 | * @param userdata: The vdec_decoder structure. 272 | * 273 | * @return true if the frame passes the checks, false otherwise 274 | */ 275 | VDEC_API bool vdec_default_input_filter(struct mbuf_coded_video_frame *frame, 276 | void *userdata); 277 | 278 | /** 279 | * Default filter for the input frame queue. 280 | * This filter does the following checks: 281 | * - frame is in a supported format 282 | * - frame timestamp is strictly monotonic 283 | * This version is intended to be used by custom filters, to avoid calls to 284 | * mbuf_coded_video_frame_get_frame_info() or get_supported_input_formats(). 285 | * 286 | * @warning This function does NOT check input validity. Arguments must not be 287 | * NULL, except for supported_formats if nb_supported_formats is zero. 288 | * 289 | * @param decoder: The base video decoder. 290 | * @param frame: The frame to filter. 291 | * @param frame_info: The associated vdef_coded_frame. 292 | * @param supported_formats: The formats supported by the implementation. 293 | * @param nb_supported_formats: The size of the supported_formats array. 294 | * 295 | * @return true if the frame passes the checks, false otherwise 296 | */ 297 | VDEC_INTERNAL_API bool vdec_default_input_filter_internal( 298 | struct vdec_decoder *decoder, 299 | struct mbuf_coded_video_frame *frame, 300 | struct vdef_coded_frame *frame_info, 301 | const struct vdef_coded_format *supported_formats, 302 | unsigned int nb_supported_formats); 303 | 304 | /** 305 | * Filter update function. 306 | * This function should be called at the end of a custom filter. It registers 307 | * that the frame was accepted. This function saves the frame timestamp for 308 | * monotonic checks, and sets the VDEC_ANCILLARY_KEY_INPUT_TIME ancillary data 309 | * on the frame. 310 | * 311 | * @param decoder: The base video decoder. 312 | * @param frame: The accepted frame. 313 | * @param frame_info: The associated vdef_coded_frame. 314 | */ 315 | VDEC_INTERNAL_API void vdec_default_input_filter_internal_confirm_frame( 316 | struct vdec_decoder *decoder, 317 | struct mbuf_coded_video_frame *frame, 318 | struct vdef_coded_frame *frame_info); 319 | 320 | 321 | VDEC_INTERNAL_API bool vdec_h264_is_idr(struct mbuf_coded_video_frame *frame, 322 | struct vdef_coded_frame *info); 323 | 324 | 325 | VDEC_INTERNAL_API 326 | int vdec_h264_write_grey_idr(struct vdec_decoder *self, 327 | struct vdef_coded_frame *in_frame_info, 328 | uint64_t *delta, 329 | uint64_t *timestamp, 330 | struct mbuf_mem *idr_mem, 331 | struct mbuf_coded_video_frame **idr_frame); 332 | 333 | 334 | VDEC_INTERNAL_API bool vdec_h265_is_idr(struct mbuf_coded_video_frame *frame, 335 | struct vdef_coded_frame *info); 336 | 337 | 338 | VDEC_INTERNAL_API int vdec_dbg_create_files(struct vdec_decoder *vdec); 339 | 340 | 341 | VDEC_INTERNAL_API int vdec_dbg_close_files(struct vdec_decoder *vdec); 342 | 343 | 344 | VDEC_INTERNAL_API int 345 | vdec_dbg_write_h264_ps(FILE *file, 346 | const uint8_t *sps, 347 | size_t sps_size, 348 | const uint8_t *pps, 349 | size_t pps_size, 350 | const struct vdef_coded_format *format); 351 | 352 | 353 | VDEC_INTERNAL_API int 354 | vdec_dbg_write_h265_ps(FILE *file, 355 | const uint8_t *vps, 356 | size_t vps_size, 357 | const uint8_t *sps, 358 | size_t sps_size, 359 | const uint8_t *pps, 360 | size_t pps_size, 361 | const struct vdef_coded_format *format); 362 | 363 | 364 | VDEC_INTERNAL_API 365 | int vdec_dbg_write_frame(FILE *file, struct mbuf_coded_video_frame *frame); 366 | 367 | 368 | VDEC_INTERNAL_API int 369 | vdec_dbg_parse_h264_ps(struct vdec_decoder *vdec, 370 | const uint8_t *sps, 371 | size_t sps_size, 372 | const uint8_t *pps, 373 | size_t pps_size, 374 | const struct vdef_coded_format *format); 375 | 376 | 377 | VDEC_INTERNAL_API int 378 | vdec_dbg_parse_h265_ps(struct vdec_decoder *vdec, 379 | const uint8_t *vps, 380 | size_t vps_size, 381 | const uint8_t *sps, 382 | size_t sps_size, 383 | const uint8_t *pps, 384 | size_t pps_size, 385 | const struct vdef_coded_format *format); 386 | 387 | 388 | VDEC_INTERNAL_API 389 | int vdec_dbg_parse_frame(struct vdec_decoder *vdec, 390 | struct mbuf_coded_video_frame *frame); 391 | 392 | 393 | VDEC_INTERNAL_API int 394 | vdec_dbg_write_yuv_frame(FILE *file, struct mbuf_raw_video_frame *frame); 395 | 396 | 397 | VDEC_INTERNAL_API void vdec_dbg_h264_nalu_begin(struct vdec_decoder *self, 398 | struct h264_nalu_header nh, 399 | enum h264_nalu_type type); 400 | 401 | 402 | VDEC_INTERNAL_API void vdec_dbg_h264_slice(struct vdec_decoder *self, 403 | struct h264_nalu_header nh, 404 | const struct h264_slice_header *sh); 405 | 406 | 407 | VDEC_INTERNAL_API void vdec_dbg_h265_nalu_begin(struct vdec_decoder *self, 408 | enum h265_nalu_type type); 409 | 410 | 411 | VDEC_INTERNAL_API struct vdec_config_impl * 412 | vdec_config_get_specific(struct vdec_config *config, 413 | enum vdec_decoder_implem implem); 414 | 415 | 416 | /** 417 | * Copy coded frame as frame info, meta data and ancillary data 418 | * without copying the data related to the NALUs. 419 | * It prevents holding the input coded frames too long 420 | * on systems with memory constraint. 421 | * @param frame: Pointer to the frame object. 422 | * @param mem: Pointer to the memory. 423 | * @param ret_obj: [out] Pointer to the new frame object. 424 | * @return 0 on success, negative errno on error. 425 | */ 426 | VDEC_INTERNAL_API int 427 | vdec_copy_coded_frame_as_metadata(struct mbuf_coded_video_frame *frame, 428 | struct mbuf_mem *mem, 429 | struct mbuf_coded_video_frame **ret_obj); 430 | 431 | 432 | #ifdef __cplusplus 433 | } 434 | #endif /* __cplusplus */ 435 | 436 | #endif /* !_VDEC_INTERNAL_H_ */ 437 | -------------------------------------------------------------------------------- /core/src/vdec_core_priv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_CORE_PRIV_H_ 28 | #define _VDEC_CORE_PRIV_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifdef _WIN32 39 | # include 40 | #else /* !_WIN32 */ 41 | # include 42 | #endif /* !_WIN32 */ 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #endif /* !_VDEC_CORE_PRIV_H_ */ 50 | -------------------------------------------------------------------------------- /core/src/vdec_dbg.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define ULOG_TAG vdec_core 28 | #include "vdec_core_priv.h" 29 | 30 | ULOG_DECLARE_TAG(ULOG_TAG); 31 | 32 | 33 | static FILE * 34 | create_file(const char *dir, void *ctx, const char *name, const char *mode) 35 | { 36 | int res; 37 | FILE *file = NULL; 38 | uint64_t epoch_sec = 0; 39 | int32_t utc_offset_sec = 0; 40 | struct tm tm; 41 | char *path = NULL; 42 | 43 | time_local_get(&epoch_sec, &utc_offset_sec); 44 | time_local_to_tm(epoch_sec, utc_offset_sec, &tm); 45 | 46 | res = asprintf(&path, 47 | "%s/vdec_%04d%02d%02d_%02d%02d%02d_%d_%p_%s", 48 | dir, 49 | tm.tm_year + 1900, 50 | tm.tm_mon + 1, 51 | tm.tm_mday, 52 | tm.tm_hour, 53 | tm.tm_min, 54 | tm.tm_sec, 55 | getpid(), 56 | ctx, 57 | name); 58 | if (res <= 0) { 59 | ULOG_ERRNO("asprintf", ENOMEM); 60 | return NULL; 61 | } 62 | 63 | file = fopen(path, mode); 64 | if (file == NULL) { 65 | ULOGW("failed to create debug file '%s': err=%d(%s)", 66 | path, 67 | errno, 68 | strerror(errno)); 69 | } 70 | 71 | free(path); 72 | return file; 73 | } 74 | 75 | 76 | void vdec_dbg_h264_nalu_begin(struct vdec_decoder *self, 77 | struct h264_nalu_header nh, 78 | enum h264_nalu_type type) 79 | { 80 | if (self->dbg.analysis == NULL) 81 | return; 82 | 83 | if ((type == H264_NALU_TYPE_SLICE) || 84 | (type == H264_NALU_TYPE_SLICE_DPA) || 85 | (type == H264_NALU_TYPE_SLICE_DPB) || 86 | (type == H264_NALU_TYPE_SLICE_DPC) || 87 | (type == H264_NALU_TYPE_SLICE_IDR)) 88 | return; 89 | 90 | fprintf(self->dbg.analysis, 91 | "%d %d %d %d %d %d %d\n", 92 | self->dbg.frame_index, 93 | nh.nal_unit_type, 94 | nh.nal_ref_idc, 95 | -1, 96 | -1, 97 | -1, 98 | -1); 99 | } 100 | 101 | 102 | void vdec_dbg_h264_slice(struct vdec_decoder *self, 103 | struct h264_nalu_header nh, 104 | const struct h264_slice_header *sh) 105 | { 106 | if (self->dbg.analysis == NULL) 107 | return; 108 | 109 | fprintf(self->dbg.analysis, 110 | "%d %d %d %d %d %d %d\n", 111 | self->dbg.frame_index, 112 | nh.nal_unit_type, 113 | nh.nal_ref_idc, 114 | sh->frame_num, 115 | sh->pic_order_cnt_lsb, 116 | H264_SLICE_TYPE(sh->slice_type), 117 | sh->first_mb_in_slice); 118 | } 119 | 120 | 121 | void vdec_dbg_h265_nalu_begin(struct vdec_decoder *self, 122 | enum h265_nalu_type type) 123 | { 124 | if (self->dbg.analysis == NULL) 125 | return; 126 | 127 | fprintf(self->dbg.analysis, 128 | "%d %d %d %d %d %d %d\n", 129 | self->dbg.frame_index, 130 | type, 131 | -1, 132 | -1, 133 | -1, 134 | -1, 135 | -1); 136 | } 137 | 138 | 139 | int vdec_dbg_create_files(struct vdec_decoder *self) 140 | { 141 | ULOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 142 | 143 | if ((self->config.dbg_flags & VDEC_DBG_FLAG_INPUT_BITSTREAM) != 0) { 144 | const char *filename = 145 | self->config.encoding == VDEF_ENCODING_H265 146 | ? "input.h265" 147 | : "input.h264"; 148 | 149 | self->dbg.input_bs = 150 | create_file(self->config.dbg_dir, self, filename, "wb"); 151 | } 152 | 153 | if ((self->config.dbg_flags & VDEC_DBG_FLAG_OUTPUT_YUV) != 0) { 154 | self->dbg.output_yuv = create_file( 155 | self->config.dbg_dir, self, "output.yuv", "wb"); 156 | } 157 | 158 | if ((self->config.dbg_flags & VDEC_DBG_FLAG_ANALYSIS) != 0) { 159 | self->dbg.analysis = create_file( 160 | self->config.dbg_dir, self, "analysis.csv", "w"); 161 | 162 | if (self->dbg.analysis != NULL) { 163 | fprintf(self->dbg.analysis, 164 | "index nal_unit_type " 165 | "nal_ref_idc frame_num pic_order_cnt_lsb " 166 | "slice_type first_mb_in_slice\n"); 167 | } 168 | } 169 | 170 | return 0; 171 | } 172 | 173 | 174 | int vdec_dbg_close_files(struct vdec_decoder *self) 175 | { 176 | ULOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 177 | 178 | if (self->dbg.input_bs != NULL) { 179 | fclose(self->dbg.input_bs); 180 | self->dbg.input_bs = NULL; 181 | } 182 | 183 | if (self->dbg.output_yuv != NULL) { 184 | fclose(self->dbg.output_yuv); 185 | self->dbg.output_yuv = NULL; 186 | } 187 | 188 | if (self->dbg.analysis != NULL) { 189 | fclose(self->dbg.analysis); 190 | self->dbg.analysis = NULL; 191 | } 192 | 193 | return 0; 194 | } 195 | 196 | 197 | static int write_ps(FILE *file, 198 | const uint8_t **ps_table, 199 | const size_t *size_table, 200 | size_t len, 201 | const struct vdef_coded_format *format) 202 | { 203 | ULOG_ERRNO_RETURN_ERR_IF(file == NULL, EINVAL); 204 | ULOG_ERRNO_RETURN_ERR_IF(ps_table == NULL, EINVAL); 205 | ULOG_ERRNO_RETURN_ERR_IF(size_table == NULL, EINVAL); 206 | ULOG_ERRNO_RETURN_ERR_IF(format == NULL, EINVAL); 207 | 208 | size_t offset = 209 | (format->data_format == VDEF_CODED_DATA_FORMAT_AVCC) ? 4 : 0; 210 | int start_code_missing = 211 | (format->data_format != VDEF_CODED_DATA_FORMAT_BYTE_STREAM); 212 | 213 | const uint8_t start_code[] = {0, 0, 0, 1}; 214 | for (size_t i = 0; i < len; ++i) { 215 | if (start_code_missing) 216 | fwrite(start_code, 1, 4, file); 217 | fwrite(&ps_table[i][offset], 1, size_table[i] - offset, file); 218 | } 219 | 220 | return 0; 221 | } 222 | 223 | 224 | int vdec_dbg_write_h264_ps(FILE *file, 225 | const uint8_t *sps, 226 | size_t sps_size, 227 | const uint8_t *pps, 228 | size_t pps_size, 229 | const struct vdef_coded_format *format) 230 | { 231 | const uint8_t *ps_table[] = {sps, pps}; 232 | size_t size_table[] = {sps_size, pps_size}; 233 | 234 | return write_ps(file, ps_table, size_table, 2, format); 235 | } 236 | 237 | 238 | int vdec_dbg_write_h265_ps(FILE *file, 239 | const uint8_t *vps, 240 | size_t vps_size, 241 | const uint8_t *sps, 242 | size_t sps_size, 243 | const uint8_t *pps, 244 | size_t pps_size, 245 | const struct vdef_coded_format *format) 246 | { 247 | const uint8_t *ps_table[] = {vps, sps, pps}; 248 | size_t size_table[] = {vps_size, sps_size, pps_size}; 249 | 250 | return write_ps(file, ps_table, size_table, 3, format); 251 | } 252 | 253 | 254 | int vdec_dbg_write_frame(FILE *file, struct mbuf_coded_video_frame *frame) 255 | { 256 | int res; 257 | struct vdef_coded_frame infos; 258 | 259 | ULOG_ERRNO_RETURN_ERR_IF(file == NULL, EINVAL); 260 | ULOG_ERRNO_RETURN_ERR_IF(frame == NULL, EINVAL); 261 | 262 | res = mbuf_coded_video_frame_get_frame_info(frame, &infos); 263 | if (res != 0) 264 | return res; 265 | 266 | enum vdef_coded_data_format fmt = infos.format.data_format; 267 | 268 | int nalu_count = mbuf_coded_video_frame_get_nalu_count(frame); 269 | if (nalu_count < 0) 270 | return nalu_count; 271 | 272 | for (int i = 0; i < nalu_count; i++) { 273 | const void *data; 274 | struct vdef_nalu nalu; 275 | res = mbuf_coded_video_frame_get_nalu(frame, i, &data, &nalu); 276 | if (res != 0) 277 | break; 278 | switch (fmt) { 279 | case VDEF_CODED_DATA_FORMAT_BYTE_STREAM: 280 | fwrite(data, 1, nalu.size, file); 281 | break; 282 | case VDEF_CODED_DATA_FORMAT_AVCC: 283 | fwrite("\x00\x00\x00\x01", 1, 4, file); 284 | fwrite((uint8_t *)data + 4, 1, nalu.size - 4, file); 285 | break; 286 | case VDEF_CODED_DATA_FORMAT_RAW_NALU: 287 | fwrite("\x00\x00\x00\x01", 1, 4, file); 288 | fwrite(data, 1, nalu.size, file); 289 | break; 290 | default: 291 | break; 292 | } 293 | res = mbuf_coded_video_frame_release_nalu(frame, i, data); 294 | if (res != 0) 295 | break; 296 | } 297 | return res; 298 | } 299 | 300 | 301 | static int parse(struct vdec_decoder *self, const uint8_t *data, size_t size) 302 | { 303 | switch (self->config.encoding) { 304 | case VDEF_ENCODING_H264: 305 | return h264_reader_parse_nalu(self->reader.h264, 0, data, size); 306 | 307 | case VDEF_ENCODING_H265: 308 | return h265_reader_parse_nalu(self->reader.h265, 0, data, size); 309 | 310 | default: 311 | return 0; 312 | } 313 | } 314 | 315 | 316 | int vdec_dbg_parse_frame(struct vdec_decoder *self, 317 | struct mbuf_coded_video_frame *frame) 318 | { 319 | int res; 320 | struct vdef_coded_frame infos; 321 | 322 | ULOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 323 | ULOG_ERRNO_RETURN_ERR_IF(frame == NULL, EINVAL); 324 | 325 | res = mbuf_coded_video_frame_get_frame_info(frame, &infos); 326 | if (res != 0) 327 | return res; 328 | 329 | enum vdef_coded_data_format fmt = infos.format.data_format; 330 | 331 | int nalu_count = mbuf_coded_video_frame_get_nalu_count(frame); 332 | if (nalu_count < 0) 333 | return nalu_count; 334 | for (int i = 0; i < nalu_count; i++) { 335 | const void *data; 336 | const uint8_t *raw_nalu; 337 | struct vdef_nalu nalu; 338 | res = mbuf_coded_video_frame_get_nalu(frame, i, &data, &nalu); 339 | if (res != 0) 340 | break; 341 | raw_nalu = data; 342 | switch (fmt) { 343 | case VDEF_CODED_DATA_FORMAT_BYTE_STREAM: 344 | case VDEF_CODED_DATA_FORMAT_AVCC: 345 | raw_nalu += 4; 346 | nalu.size -= 4; 347 | break; 348 | default: 349 | break; 350 | } 351 | res = parse(self, raw_nalu, nalu.size); 352 | int res2 = mbuf_coded_video_frame_release_nalu(frame, i, data); 353 | if (res2 != 0) { 354 | res = res2; 355 | break; 356 | } 357 | } 358 | 359 | self->dbg.frame_index++; 360 | return res; 361 | } 362 | 363 | 364 | int vdec_dbg_write_yuv_frame(FILE *file, struct mbuf_raw_video_frame *frame) 365 | { 366 | int res; 367 | struct vdef_raw_frame infos; 368 | 369 | ULOG_ERRNO_RETURN_ERR_IF(file == NULL, EINVAL); 370 | ULOG_ERRNO_RETURN_ERR_IF(frame == NULL, EINVAL); 371 | 372 | res = mbuf_raw_video_frame_get_frame_info(frame, &infos); 373 | if (res != 0) 374 | return res; 375 | 376 | int nplanes = vdef_get_raw_frame_plane_count(&infos.format); 377 | 378 | /* TODO: This function will write the frame as-is, including strides. 379 | * we could check for strides, and if present, remove them using 380 | * mbuf_raw_video_frame_copy() in the future */ 381 | 382 | for (int i = 0; i < nplanes; i++) { 383 | const void *data; 384 | size_t len; 385 | res = mbuf_raw_video_frame_get_plane(frame, i, &data, &len); 386 | if (res != 0) 387 | break; 388 | fwrite(data, 1, len, file); 389 | res = mbuf_raw_video_frame_release_plane(frame, i, data); 390 | if (res != 0) 391 | break; 392 | } 393 | 394 | return res; 395 | } 396 | -------------------------------------------------------------------------------- /core/src/vdec_enums.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define ULOG_TAG vdec_core 28 | #include "vdec_core_priv.h" 29 | 30 | 31 | const char *vdec_decoder_implem_str(enum vdec_decoder_implem implem) 32 | { 33 | switch (implem) { 34 | case VDEC_DECODER_IMPLEM_FFMPEG: 35 | return "FFMPEG"; 36 | case VDEC_DECODER_IMPLEM_MEDIACODEC: 37 | return "MEDIACODEC"; 38 | case VDEC_DECODER_IMPLEM_VIDEOTOOLBOX: 39 | return "VIDEOTOOLBOX"; 40 | case VDEC_DECODER_IMPLEM_HISI: 41 | return "HISI"; 42 | case VDEC_DECODER_IMPLEM_AML: 43 | return "AML"; 44 | case VDEC_DECODER_IMPLEM_TURBOJPEG: 45 | return "TURBOJPEG"; 46 | case VDEC_DECODER_IMPLEM_QCOM: 47 | return "QCOM"; 48 | default: 49 | return "UNKNOWN"; 50 | } 51 | } 52 | 53 | 54 | struct vdec_config_impl * 55 | vdec_config_get_specific(struct vdec_config *config, 56 | enum vdec_decoder_implem implem) 57 | { 58 | /* Check if specific config is present */ 59 | if (!config->implem_cfg) 60 | return NULL; 61 | 62 | /* Check if implementation is the right one */ 63 | if (config->implem != implem) { 64 | ULOGI("specific config found, but implementation is %s " 65 | "instead of %s. ignoring specific config", 66 | vdec_decoder_implem_str(config->implem), 67 | vdec_decoder_implem_str(implem)); 68 | return NULL; 69 | } 70 | 71 | /* Check if specific config implementation matches the base one */ 72 | if (config->implem_cfg->implem != config->implem) { 73 | ULOGW("specific config implem (%s) does not match" 74 | " base config implem (%s). ignoring specific config", 75 | vdec_decoder_implem_str(config->implem_cfg->implem), 76 | vdec_decoder_implem_str(config->implem)); 77 | return NULL; 78 | } 79 | 80 | /* All tests passed, return specific config */ 81 | return config->implem_cfg; 82 | } 83 | -------------------------------------------------------------------------------- /core/src/vdec_format.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define ULOG_TAG vdec_core 28 | #include "vdec_core_priv.h" 29 | #include 30 | 31 | 32 | int vdec_format_convert(struct mbuf_coded_video_frame *frame, 33 | const struct vdef_coded_format *target_format) 34 | { 35 | int res; 36 | uint8_t *data; 37 | size_t len; 38 | struct vdef_coded_frame info; 39 | const struct vdef_coded_format *current_format; 40 | 41 | ULOG_ERRNO_RETURN_ERR_IF(frame == NULL, EINVAL); 42 | ULOG_ERRNO_RETURN_ERR_IF(target_format == NULL, EINVAL); 43 | 44 | res = mbuf_coded_video_frame_get_frame_info(frame, &info); 45 | if (res < 0) { 46 | ULOG_ERRNO("mbuf_coded_video_frame_get_frame_info", -res); 47 | return res; 48 | } 49 | current_format = &info.format; 50 | 51 | /* No conversion needed */ 52 | if (vdef_coded_format_cmp(current_format, target_format)) 53 | return 0; 54 | 55 | res = mbuf_coded_video_frame_get_rw_packed_buffer( 56 | frame, (void **)&data, &len); 57 | if (res < 0) { 58 | ULOG_ERRNO("mbuf_coded_video_frame_get_rw_packed_buffer", -res); 59 | goto out; 60 | } 61 | 62 | if (current_format->encoding != target_format->encoding) { 63 | res = -ENOSYS; 64 | ULOG_ERRNO("encoding mismatch", -res); 65 | goto out; 66 | } 67 | if ((current_format->encoding != VDEF_ENCODING_H264) && 68 | (current_format->encoding != VDEF_ENCODING_H265)) { 69 | res = -ENOSYS; 70 | ULOG_ERRNO("unsupported encoding", -res); 71 | goto out; 72 | } 73 | 74 | /* Only support byte stream to AVCC/HVCC or AVCC/HVCC to byte stream */ 75 | if ((current_format->data_format == VDEF_CODED_DATA_FORMAT_RAW_NALU) || 76 | (target_format->data_format == VDEF_CODED_DATA_FORMAT_RAW_NALU)) { 77 | res = -ENOSYS; 78 | ULOG_ERRNO("cannot convert raw NALU formats", -res); 79 | goto out; 80 | } 81 | 82 | if (current_format->data_format == VDEF_CODED_DATA_FORMAT_AVCC && 83 | target_format->data_format == VDEF_CODED_DATA_FORMAT_BYTE_STREAM) { 84 | /* AVCC/HVCC to byte stream */ 85 | switch (current_format->encoding) { 86 | case VDEF_ENCODING_H264: 87 | res = h264_avcc_to_byte_stream(data, len); 88 | if (res < 0) { 89 | ULOG_ERRNO("h264_avcc_to_byte_stream", -res); 90 | goto out; 91 | } 92 | break; 93 | case VDEF_ENCODING_H265: 94 | res = h265_hvcc_to_byte_stream(data, len); 95 | if (res < 0) { 96 | ULOG_ERRNO("h265_hvcc_to_byte_stream", -res); 97 | goto out; 98 | } 99 | break; 100 | default: 101 | break; 102 | } 103 | } else if (current_format->data_format == 104 | VDEF_CODED_DATA_FORMAT_BYTE_STREAM && 105 | target_format->data_format == VDEF_CODED_DATA_FORMAT_AVCC) { 106 | /* Byte stream to AVCC */ 107 | switch (current_format->encoding) { 108 | case VDEF_ENCODING_H264: 109 | res = h264_byte_stream_to_avcc(data, len); 110 | if (res < 0) { 111 | ULOG_ERRNO("h264_byte_stream_to_avcc", -res); 112 | goto out; 113 | } 114 | break; 115 | case VDEF_ENCODING_H265: 116 | res = h265_byte_stream_to_hvcc(data, len); 117 | if (res < 0) { 118 | ULOG_ERRNO("h265_byte_stream_to_hvcc", -res); 119 | goto out; 120 | } 121 | break; 122 | default: 123 | break; 124 | } 125 | } else { 126 | res = -ENOSYS; 127 | ULOG_ERRNO("unsupported conversion (%s to %s)", 128 | -res, 129 | vdef_coded_data_format_to_str( 130 | current_format->data_format), 131 | vdef_coded_data_format_to_str( 132 | target_format->data_format)); 133 | return res; 134 | } 135 | 136 | 137 | out: 138 | mbuf_coded_video_frame_release_rw_packed_buffer(frame, data); 139 | return res; 140 | } 141 | 142 | 143 | bool vdec_is_sync_frame(struct mbuf_coded_video_frame *frame, 144 | struct vdef_coded_frame *info) 145 | { 146 | ULOG_ERRNO_RETURN_VAL_IF(frame == NULL, EINVAL, false); 147 | ULOG_ERRNO_RETURN_VAL_IF(info == NULL, EINVAL, false); 148 | 149 | /* If the frame is declared as an IDR, trust it */ 150 | if (info->type == VDEF_CODED_FRAME_TYPE_IDR) 151 | return true; 152 | /* If the frame is declared as anything else, trust it too */ 153 | if (info->type != VDEF_CODED_FRAME_TYPE_UNKNOWN) 154 | return false; 155 | 156 | /* If the frame is of type UNKNOWN, parse the frame */ 157 | switch (info->format.encoding) { 158 | case VDEF_ENCODING_H264: 159 | return vdec_h264_is_idr(frame, info); 160 | case VDEF_ENCODING_H265: 161 | return vdec_h265_is_idr(frame, info); 162 | default: 163 | ULOGE("unsupported encoding (%s)", 164 | vdef_encoding_to_str(info->format.encoding)); 165 | return false; 166 | } 167 | } 168 | 169 | 170 | void vdec_call_frame_output_cb(struct vdec_decoder *base, 171 | int status, 172 | struct mbuf_raw_video_frame *frame) 173 | { 174 | if (!base->cbs.frame_output) 175 | return; 176 | 177 | base->cbs.frame_output(base, status, frame, base->userdata); 178 | if (status == 0 && frame != NULL) 179 | atomic_fetch_add(&base->counters.out, 1); 180 | } 181 | 182 | 183 | void vdec_call_flush_cb(struct vdec_decoder *base) 184 | { 185 | /* Reset last_timestamp */ 186 | atomic_store(&base->last_timestamp, UINT64_MAX); 187 | 188 | /* Call the application callback */ 189 | if (!base->cbs.flush) 190 | return; 191 | 192 | base->cbs.flush(base, base->userdata); 193 | } 194 | 195 | 196 | void vdec_call_stop_cb(struct vdec_decoder *base) 197 | { 198 | if (!base->cbs.stop) 199 | return; 200 | 201 | base->cbs.stop(base, base->userdata); 202 | } 203 | 204 | 205 | bool vdec_default_input_filter(struct mbuf_coded_video_frame *frame, 206 | void *userdata) 207 | { 208 | int ret; 209 | bool accept; 210 | struct vdec_decoder *decoder = userdata; 211 | const struct vdef_coded_format *supported_formats; 212 | struct vdef_coded_frame frame_info; 213 | 214 | if (!frame || !decoder) 215 | return false; 216 | 217 | ret = mbuf_coded_video_frame_get_frame_info(frame, &frame_info); 218 | if (ret != 0) 219 | return false; 220 | 221 | ret = decoder->ops->get_supported_input_formats(&supported_formats); 222 | if (ret < 0) 223 | return false; 224 | accept = vdec_default_input_filter_internal( 225 | decoder, frame, &frame_info, supported_formats, ret); 226 | if (accept) 227 | vdec_default_input_filter_internal_confirm_frame( 228 | decoder, frame, &frame_info); 229 | return accept; 230 | } 231 | 232 | 233 | bool vdec_default_input_filter_internal( 234 | struct vdec_decoder *decoder, 235 | struct mbuf_coded_video_frame *frame, 236 | struct vdef_coded_frame *frame_info, 237 | const struct vdef_coded_format *supported_formats, 238 | unsigned int nb_supported_formats) 239 | { 240 | uint64_t last_timestamp; 241 | if (!vdef_coded_format_intersect(&frame_info->format, 242 | supported_formats, 243 | nb_supported_formats)) { 244 | ULOG_ERRNO( 245 | "unsupported format:" 246 | " " VDEF_CODED_FORMAT_TO_STR_FMT, 247 | EPROTO, 248 | VDEF_CODED_FORMAT_TO_STR_ARG(&frame_info->format)); 249 | return false; 250 | } 251 | 252 | last_timestamp = atomic_load(&decoder->last_timestamp); 253 | 254 | if (frame_info->info.timestamp <= last_timestamp && 255 | last_timestamp != UINT64_MAX) { 256 | ULOG_ERRNO("non-strictly-monotonic timestamp (%" PRIu64 257 | " <= %" PRIu64 ")", 258 | EPROTO, 259 | frame_info->info.timestamp, 260 | last_timestamp); 261 | return false; 262 | } 263 | 264 | return true; 265 | } 266 | 267 | 268 | void vdec_default_input_filter_internal_confirm_frame( 269 | struct vdec_decoder *decoder, 270 | struct mbuf_coded_video_frame *frame, 271 | struct vdef_coded_frame *frame_info) 272 | { 273 | int err; 274 | uint64_t ts_us; 275 | struct timespec cur_ts = {0, 0}; 276 | 277 | /* Save frame timestamp to last_timestamp */ 278 | uint_least64_t last_timestamp = frame_info->info.timestamp; 279 | atomic_store(&decoder->last_timestamp, last_timestamp); 280 | atomic_fetch_add(&decoder->counters.in, 1); 281 | 282 | /* Set the input time ancillary data to the frame */ 283 | time_get_monotonic(&cur_ts); 284 | time_timespec_to_us(&cur_ts, &ts_us); 285 | err = mbuf_coded_video_frame_add_ancillary_buffer( 286 | frame, VDEC_ANCILLARY_KEY_INPUT_TIME, &ts_us, sizeof(ts_us)); 287 | if (err < 0) 288 | ULOG_ERRNO("mbuf_coded_video_frame_add_ancillary_buffer", -err); 289 | } 290 | 291 | 292 | int vdec_copy_coded_frame_as_metadata(struct mbuf_coded_video_frame *frame, 293 | struct mbuf_mem *mem, 294 | struct mbuf_coded_video_frame **ret_obj) 295 | { 296 | int ret = 0, err; 297 | struct vdef_coded_frame info; 298 | struct vmeta_frame *metadata = NULL; 299 | struct mbuf_coded_video_frame *meta_frame = NULL; 300 | 301 | ULOG_ERRNO_RETURN_ERR_IF(frame == NULL, EINVAL); 302 | ULOG_ERRNO_RETURN_ERR_IF(mem == NULL, EINVAL); 303 | ULOG_ERRNO_RETURN_ERR_IF(ret_obj == NULL, EINVAL); 304 | 305 | ret = mbuf_coded_video_frame_get_frame_info(frame, &info); 306 | if (ret < 0) { 307 | ULOG_ERRNO("mbuf_coded_video_frame_new", -ret); 308 | return ret; 309 | } 310 | 311 | ret = mbuf_coded_video_frame_new(&info, &meta_frame); 312 | if (ret < 0) { 313 | ULOG_ERRNO("mbuf_coded_video_frame_new", -ret); 314 | return ret; 315 | } 316 | 317 | /* libmedia-buffers does not accept to finalize a mbuf_coded_video_frame 318 | * that does not provide any NALU */ 319 | struct vdef_nalu nalu = { 320 | .size = 0, 321 | .importance = 0, 322 | }; 323 | ret = mbuf_coded_video_frame_add_nalu(meta_frame, mem, 0, &nalu); 324 | if (ret < 0) { 325 | ULOG_ERRNO("mbuf_coded_video_frame_add_nalu", -ret); 326 | goto failure; 327 | } 328 | 329 | /* Copy ancillary data */ 330 | ret = mbuf_coded_video_frame_foreach_ancillary_data( 331 | frame, 332 | mbuf_coded_video_frame_ancillary_data_copier, 333 | meta_frame); 334 | if (ret < 0) { 335 | ULOG_ERRNO("mbuf_coded_video_frame_foreach_ancillary_data", 336 | -ret); 337 | goto failure; 338 | } 339 | 340 | /* Frame metadata */ 341 | ret = mbuf_coded_video_frame_get_metadata(frame, &metadata); 342 | if (ret == 0) { 343 | ret = mbuf_coded_video_frame_set_metadata(meta_frame, metadata); 344 | vmeta_frame_unref(metadata); 345 | if (ret < 0) { 346 | ULOG_ERRNO("mbuf_coded_video_frame_set_metadata", -ret); 347 | goto failure; 348 | } 349 | } else if (ret != -ENOENT) { 350 | ULOG_ERRNO("mbuf_coded_video_frame_get_metadata", -ret); 351 | goto failure; 352 | } 353 | 354 | ret = mbuf_coded_video_frame_finalize(meta_frame); 355 | if (ret < 0) { 356 | ULOG_ERRNO("mbuf_coded_video_frame_finalize", -ret); 357 | goto failure; 358 | } 359 | 360 | *ret_obj = meta_frame; 361 | 362 | failure: 363 | if ((ret < 0) && (meta_frame)) { 364 | err = mbuf_coded_video_frame_unref(meta_frame); 365 | if (err < 0) 366 | ULOG_ERRNO("mbuf_coded_video_frame_unref", -ret); 367 | } 368 | 369 | return ret; 370 | } 371 | -------------------------------------------------------------------------------- /core/src/vdec_h264.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define ULOG_TAG vdec_core 28 | #include "vdec_core_priv.h" 29 | 30 | 31 | bool vdec_h264_is_idr(struct mbuf_coded_video_frame *frame, 32 | struct vdef_coded_frame *info) 33 | { 34 | int err = 0; 35 | int nalu_count; 36 | 37 | ULOG_ERRNO_RETURN_VAL_IF(frame == NULL, EINVAL, false); 38 | ULOG_ERRNO_RETURN_VAL_IF(info == NULL, EINVAL, false); 39 | 40 | nalu_count = mbuf_coded_video_frame_get_nalu_count(frame); 41 | if (nalu_count < 0) { 42 | err = nalu_count; 43 | ULOG_ERRNO("mbuf_coded_video_frame_get_nalu_count", -err); 44 | return false; 45 | } 46 | for (int i = 0; i < nalu_count; i++) { 47 | const void *data; 48 | const uint8_t *raw_nalu; 49 | struct vdef_nalu nalu; 50 | 51 | err = mbuf_coded_video_frame_get_nalu(frame, i, &data, &nalu); 52 | if (err < 0) { 53 | ULOG_ERRNO("mbuf_coded_video_frame_get_nalu", -err); 54 | return false; 55 | } 56 | 57 | /* If the type is "unknown", read it from data */ 58 | if (nalu.h264.type == H264_NALU_TYPE_UNKNOWN) { 59 | raw_nalu = data; 60 | if (info->format.data_format != 61 | VDEF_CODED_DATA_FORMAT_RAW_NALU) 62 | raw_nalu += 4; 63 | nalu.h264.type = 64 | (enum h264_nalu_type)(*raw_nalu & 0x1F); 65 | } 66 | 67 | err = mbuf_coded_video_frame_release_nalu(frame, i, data); 68 | if (err < 0) { 69 | ULOG_ERRNO("mbuf_coded_video_frame_release_nalu", -err); 70 | return false; 71 | } 72 | 73 | /* As for each frame, trust the nalu type if given */ 74 | if (nalu.h264.type == H264_NALU_TYPE_SLICE_IDR) 75 | return true; 76 | else if (nalu.h264.type == H264_NALU_TYPE_SLICE) 77 | return false; 78 | } 79 | return false; 80 | } 81 | 82 | 83 | int vdec_h264_write_grey_idr(struct vdec_decoder *self, 84 | struct vdef_coded_frame *in_frame_info, 85 | uint64_t *delta, 86 | uint64_t *timestamp, 87 | struct mbuf_mem *idr_mem, 88 | struct mbuf_coded_video_frame **idr_frame) 89 | { 90 | int ret; 91 | struct h264_slice_header *sh = NULL; 92 | uint32_t mb_total, sc; 93 | struct h264_bitstream bs; 94 | struct h264_ctx *ctx = h264_reader_get_ctx(self->reader.h264); 95 | uint8_t *data; 96 | size_t size = 0; 97 | struct vdef_coded_frame idr_frame_info; 98 | struct vdef_nalu nalu; 99 | 100 | ULOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 101 | ULOG_ERRNO_RETURN_ERR_IF(in_frame_info == NULL, EINVAL); 102 | ULOG_ERRNO_RETURN_ERR_IF(delta == NULL, EINVAL); 103 | ULOG_ERRNO_RETURN_ERR_IF(timestamp == NULL, EINVAL); 104 | ULOG_ERRNO_RETURN_ERR_IF(idr_mem == NULL, EINVAL); 105 | ULOG_ERRNO_RETURN_ERR_IF(idr_frame == NULL, EINVAL); 106 | 107 | *idr_frame = NULL; 108 | 109 | if (!self->configured) { 110 | ULOGW("%s: decoder is not configured", __func__); 111 | return -EAGAIN; 112 | } 113 | 114 | idr_frame_info = *in_frame_info; 115 | idr_frame_info.info.capture_timestamp = 0; 116 | idr_frame_info.type = VDEF_CODED_FRAME_TYPE_IDR; 117 | idr_frame_info.info.flags = VDEF_FRAME_FLAG_SILENT; 118 | 119 | *delta = (in_frame_info->info.timestamp == 0) ? 1 : 0; 120 | if (in_frame_info->info.timestamp != 0) 121 | idr_frame_info.info.timestamp--; 122 | *timestamp = idr_frame_info.info.timestamp; 123 | 124 | /* Start NALU */ 125 | ret = h264_ctx_clear_nalu(ctx); 126 | if (ret < 0) { 127 | ULOG_ERRNO("h264_ctx_clear_nalu", -ret); 128 | return ret; 129 | } 130 | 131 | /* Setup NALU header */ 132 | struct h264_nalu_header nh = { 133 | .nal_ref_idc = 3, 134 | .nal_unit_type = H264_NALU_TYPE_SLICE_IDR, 135 | }; 136 | ret = h264_ctx_set_nalu_header(ctx, &nh); 137 | if (ret < 0) { 138 | ULOG_ERRNO("h264_ctx_set_nalu_header", -ret); 139 | goto out; 140 | } 141 | 142 | /* Setup slice header */ 143 | sh = calloc(1, sizeof(*sh)); 144 | if (sh == NULL) { 145 | ret = -ENOMEM; 146 | ULOG_ERRNO("calloc", -ret); 147 | goto out; 148 | } 149 | 150 | sh->first_mb_in_slice = 0; 151 | sh->slice_type = H264_SLICE_TYPE_I; 152 | sh->frame_num = 0; 153 | sh->pic_order_cnt_lsb = 0; 154 | sh->redundant_pic_cnt = 0; 155 | sh->direct_spatial_mv_pred_flag = 0; 156 | sh->slice_qp_delta = 0; 157 | sh->disable_deblocking_filter_idc = 2; 158 | sh->slice_alpha_c0_offset_div2 = 0; 159 | sh->slice_beta_offset_div2 = 0; 160 | sh->drpm.long_term_reference_flag = 161 | (in_frame_info->info.flags & VDEF_FRAME_FLAG_USES_LTR) ? 1 : 0; 162 | ret = h264_ctx_set_slice_header(ctx, sh); 163 | if (ret < 0) { 164 | ULOG_ERRNO("h264_ctx_set_slice_header", -ret); 165 | goto out; 166 | } 167 | 168 | /* Setup bitstream */ 169 | ret = mbuf_mem_get_data(idr_mem, (void **)&data, &size); 170 | if (ret < 0) { 171 | ULOG_ERRNO("mbuf_mem_get_data", -ret); 172 | goto out; 173 | } 174 | 175 | memset(&bs, 0, sizeof(bs)); 176 | if (size <= 4) { 177 | ret = -ENOBUFS; 178 | ULOG_ERRNO("", -ret); 179 | goto out; 180 | } 181 | 182 | h264_bs_init(&bs, data + 4, size - 4, 1); 183 | 184 | /* Write slice */ 185 | mb_total = VDEF_ROUND_UP(self->video_info.resolution.height, 16) * 186 | VDEF_ROUND_UP(self->video_info.resolution.width, 16); 187 | 188 | h264_write_grey_i_slice(&bs, ctx, mb_total); 189 | 190 | switch (in_frame_info->format.data_format) { 191 | case VDEF_CODED_DATA_FORMAT_AVCC: 192 | sc = htonl(bs.off); 193 | memcpy(data, &sc, sizeof(sc)); 194 | break; 195 | case VDEF_CODED_DATA_FORMAT_BYTE_STREAM: 196 | sc = htonl(0x00000001); 197 | memcpy(data, &sc, sizeof(sc)); 198 | break; 199 | default: 200 | ret = -ENOSYS; 201 | ULOG_ERRNO("unsupported data format", -ret); 202 | goto out; 203 | } 204 | 205 | ret = mbuf_coded_video_frame_new(&idr_frame_info, idr_frame); 206 | if (ret < 0) { 207 | ULOG_ERRNO("mbuf_coded_video_frame_new", -ret); 208 | goto out; 209 | } 210 | nalu = (struct vdef_nalu){ 211 | .size = bs.off + 4, 212 | .importance = 0, 213 | .h264.type = H264_NALU_TYPE_SLICE_IDR, 214 | .h264.slice_type = H264_SLICE_TYPE_I, 215 | .h264.slice_mb_count = mb_total, 216 | }; 217 | ret = mbuf_coded_video_frame_add_nalu(*idr_frame, idr_mem, 0, &nalu); 218 | if (ret < 0) { 219 | ULOG_ERRNO("mbuf_coded_video_frame_add_nalu", -ret); 220 | goto out; 221 | } 222 | ret = mbuf_coded_video_frame_finalize(*idr_frame); 223 | if (ret < 0) { 224 | ULOG_ERRNO("mbuf_coded_video_frame_finalize", -ret); 225 | goto out; 226 | } 227 | 228 | out: 229 | if (ret != 0) { 230 | if (*idr_frame != NULL) { 231 | mbuf_coded_video_frame_unref(*idr_frame); 232 | *idr_frame = NULL; 233 | } 234 | } 235 | free(sh); 236 | return ret; 237 | } 238 | -------------------------------------------------------------------------------- /core/src/vdec_h265.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define ULOG_TAG vdec_core 28 | #include "vdec_core_priv.h" 29 | 30 | 31 | bool vdec_h265_is_idr(struct mbuf_coded_video_frame *frame, 32 | struct vdef_coded_frame *info) 33 | { 34 | int err = 0; 35 | int nalu_count; 36 | 37 | ULOG_ERRNO_RETURN_VAL_IF(frame == NULL, EINVAL, false); 38 | ULOG_ERRNO_RETURN_VAL_IF(info == NULL, EINVAL, false); 39 | 40 | nalu_count = mbuf_coded_video_frame_get_nalu_count(frame); 41 | if (nalu_count < 0) { 42 | err = nalu_count; 43 | ULOG_ERRNO("mbuf_coded_video_frame_get_nalu_count", -err); 44 | return false; 45 | } 46 | for (int i = 0; i < nalu_count; i++) { 47 | const void *data; 48 | const uint8_t *raw_nalu; 49 | struct vdef_nalu nalu; 50 | 51 | err = mbuf_coded_video_frame_get_nalu(frame, i, &data, &nalu); 52 | if (err < 0) { 53 | ULOG_ERRNO("mbuf_coded_video_frame_get_nalu", -err); 54 | return false; 55 | } 56 | 57 | /* If the type is "unknown", read it from data */ 58 | if (nalu.h265.type == H265_NALU_TYPE_UNKNOWN) { 59 | raw_nalu = data; 60 | if (info->format.data_format != 61 | VDEF_CODED_DATA_FORMAT_RAW_NALU) 62 | raw_nalu += 4; 63 | nalu.h265.type = 64 | (enum h265_nalu_type)((*raw_nalu & 0x3E) >> 1); 65 | } 66 | 67 | err = mbuf_coded_video_frame_release_nalu(frame, i, data); 68 | if (err < 0) { 69 | ULOG_ERRNO("mbuf_coded_video_frame_release_nalu", -err); 70 | return false; 71 | } 72 | 73 | /* As for each frame, trust the nalu type if given */ 74 | switch (nalu.h265.type) { 75 | case H265_NALU_TYPE_IDR_W_RADL: 76 | case H265_NALU_TYPE_IDR_N_LP: 77 | return true; 78 | case H265_NALU_TYPE_BLA_W_LP: 79 | case H265_NALU_TYPE_BLA_W_RADL: 80 | case H265_NALU_TYPE_BLA_N_LP: 81 | case H265_NALU_TYPE_CRA_NUT: 82 | return false; 83 | default: 84 | break; 85 | } 86 | } 87 | return false; 88 | } 89 | -------------------------------------------------------------------------------- /ffmpeg/include/video-decode/vdec_ffmpeg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_FFMPEG_H_ 28 | #define _VDEC_FFMPEG_H_ 29 | 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif /* __cplusplus */ 35 | 36 | /* To be used for all public API */ 37 | #ifdef VDEC_API_EXPORTS 38 | # ifdef _WIN32 39 | # define VDEC_API __declspec(dllexport) 40 | # else /* !_WIN32 */ 41 | # define VDEC_API __attribute__((visibility("default"))) 42 | # endif /* !_WIN32 */ 43 | #else /* !VDEC_API_EXPORTS */ 44 | # define VDEC_API 45 | #endif /* !VDEC_API_EXPORTS */ 46 | 47 | 48 | #define VDEC_FFMPEG_NB_SUPPORTED_FORMATS 2 49 | 50 | 51 | extern VDEC_API const struct vdec_ops vdec_ffmpeg_ops; 52 | 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif /* __cplusplus */ 57 | 58 | 59 | #endif /* !_VDEC_FFMPEG_H_ */ 60 | -------------------------------------------------------------------------------- /ffmpeg/src/vdec_ffmpeg_priv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_FFMPEG_PRIV_H_ 28 | #define _VDEC_FFMPEG_PRIV_H_ 29 | 30 | #ifdef _WIN32 31 | # include 32 | #else /* !_WIN32 */ 33 | # include 34 | #endif /* !_WIN32 */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #define VDEC_FFMPEG_DEFAULT_THREAD_COUNT 8 52 | 53 | #define VDEC_MSG_FLUSH 'f' 54 | #define VDEC_MSG_STOP 's' 55 | 56 | 57 | struct vdec_ffmpeg { 58 | struct vdec_decoder *base; 59 | struct mbuf_coded_video_frame_queue *in_queue; 60 | struct mbuf_coded_video_frame_queue *decoder_queue; 61 | struct mbuf_raw_video_frame_queue *out_queue; 62 | struct pomp_evt *out_queue_evt; 63 | AVCodecContext *avcodec; 64 | AVBufferRef *hw_device_ctx; 65 | AVPacket *avpacket; 66 | AVFrame *dummy_frame; 67 | atomic_int flushing; 68 | 69 | pthread_t thread; 70 | atomic_int thread_launched; 71 | atomic_int should_stop; 72 | atomic_int flush; 73 | atomic_int flush_discard; 74 | struct mbox *mbox; 75 | atomic_int need_sync; 76 | }; 77 | 78 | #endif /* _VDEC_FFMPEG_PRIV_H_ */ 79 | -------------------------------------------------------------------------------- /include/video-decode/vdec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_H_ 28 | #define _VDEC_H_ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif /* __cplusplus */ 40 | 41 | /* To be used for all public API */ 42 | #ifdef VDEC_API_EXPORTS 43 | # ifdef _WIN32 44 | # define VDEC_API __declspec(dllexport) 45 | # else /* !_WIN32 */ 46 | # define VDEC_API __attribute__((visibility("default"))) 47 | # endif /* !_WIN32 */ 48 | #else /* !VDEC_API_EXPORTS */ 49 | # define VDEC_API 50 | #endif /* !VDEC_API_EXPORTS */ 51 | 52 | 53 | /** 54 | * Get the supported input buffer data formats for all decoder implementations. 55 | * The returned formats array is a static array whose size is the return value 56 | * of this function. If this function returns an error (negative errno value), 57 | * then the value of *formats is undefined. 58 | * The vdec_get_auto_implem_by_coded_format function can then be used to find 59 | * a suitable implementation for a given format. 60 | * @param formats: pointer to the supported formats list (output) 61 | * @return the size of the formats array, or a negative errno on error. 62 | */ 63 | VDEC_API int 64 | vdec_get_all_supported_input_formats(const struct vdef_coded_format **formats); 65 | 66 | 67 | /** 68 | * Get the supported input buffer data formats for the given 69 | * decoder implementation. 70 | * Each implementation supports at least one input format, 71 | * and optionally more. All input buffers need to be in one of 72 | * the supported formats, otherwise they will be discarded. 73 | * The returned formats array is a static array whose size is the return value 74 | * of this function. If this function returns an error (negative errno value), 75 | * then the value of *formats is undefined. 76 | * @param implem: decoder implementation 77 | * @param formats: pointer to the supported formats list (output) 78 | * @return the size of the formats array, or a negative errno on error. 79 | */ 80 | VDEC_API int 81 | vdec_get_supported_input_formats(enum vdec_decoder_implem implem, 82 | const struct vdef_coded_format **formats); 83 | 84 | 85 | /** 86 | * Get the implementation that will be chosen in case VDEC_DECODER_IMPLEM_AUTO 87 | * is used. 88 | * @return the decoder implementation, or VDEC_DECODER_IMPLEM_AUTO in case of 89 | * error 90 | */ 91 | VDEC_API enum vdec_decoder_implem vdec_get_auto_implem(void); 92 | 93 | 94 | /** 95 | * Get an implementation for a given coded format 96 | * @param format: coded format to support 97 | * @return the decoder implementation, or VDEC_DECODER_IMPLEM_AUTO in case of 98 | * error 99 | */ 100 | VDEC_API enum vdec_decoder_implem 101 | vdec_get_auto_implem_by_coded_format(struct vdef_coded_format *format); 102 | 103 | /** 104 | * Create a decoder instance. 105 | * The configuration and callbacks structures must be filled. 106 | * The instance handle is returned through the ret_obj parameter. 107 | * When no longer needed, the instance must be freed using the 108 | * vdec_destroy() function. 109 | * @param loop: event loop to use 110 | * @param config: decoder configuration 111 | * @param cbs: decoder callback functions 112 | * @param userdata: callback functions user data (optional, can be null) 113 | * @param ret_obj: decoder instance handle (output) 114 | * @return 0 on success, negative errno value in case of error 115 | */ 116 | VDEC_API int vdec_new(struct pomp_loop *loop, 117 | const struct vdec_config *config, 118 | const struct vdec_cbs *cbs, 119 | void *userdata, 120 | struct vdec_decoder **ret_obj); 121 | 122 | 123 | /** 124 | * Flush the decoder. 125 | * This function flushes all queues and optionally discards all buffers 126 | * retained by the decoder. If the buffers are not discarded the frame 127 | * output callback is called for each frame when the decoding is complete. 128 | * The function is asynchronous and returns immediately. When flushing is 129 | * complete the flush callback function is called if defined. After flushing 130 | * the decoder new input buffers can still be queued but should start with a 131 | * synchronization frame (e.g. IDR frame or start of refresh). 132 | * @param self: decoder instance handle 133 | * @param discard: if null, all pending buffers are output, otherwise they 134 | * are discarded 135 | * @return 0 on success, negative errno value in case of error 136 | */ 137 | VDEC_API int vdec_flush(struct vdec_decoder *self, int discard); 138 | 139 | 140 | /** 141 | * Stop the decoder. 142 | * This function stops any running threads. The function is asynchronous and 143 | * returns immediately. When stopping is complete the stop callback function 144 | * is called if defined. After stopping the decoder no new input buffers 145 | * can be queued and the decoder instance must be freed using the 146 | * vdec_destroy() function. 147 | * @param self: decoder instance handle 148 | * @return 0 on success, negative errno value in case of error 149 | */ 150 | VDEC_API int vdec_stop(struct vdec_decoder *self); 151 | 152 | 153 | /** 154 | * Free a decoder instance. 155 | * This function frees all resources associated with a decoder instance. 156 | * @note this function blocks until all internal threads (if any) can be 157 | * joined; therefore the application should call vdec_stop() and wait for 158 | * the stop callback function to be called before calling vdec_destroy(). 159 | * @param self: decoder instance handle 160 | * @return 0 on success, negative errno value in case of error 161 | */ 162 | VDEC_API int vdec_destroy(struct vdec_decoder *self); 163 | 164 | 165 | /** 166 | * Set the JPEG parameters for decoding. 167 | * This function must be called prior to decoding (i.e. pushing buffer into 168 | * the input queue). The ownership of the format_info struct stays 169 | * with the caller. It is the caller's responsibility to ensure that the 170 | * instance is configured to decode a MJPEG/JPEG stream. 171 | * @param self decoder instance handle 172 | * @param[in] format_info: image format information 173 | * @return 0 on success, negative errno value in case of error 174 | */ 175 | VDEC_API int vdec_set_jpeg_params(struct vdec_decoder *self, 176 | const struct vdef_format_info *format_info); 177 | 178 | 179 | /** 180 | * Set the H264 parameter sets for decoding. 181 | * This function must be called prior to decoding (i.e. pushing buffer into 182 | * the input queue) with the H.264 SPS and PPS. The SPS and PPS data will be 183 | * copied internally if necessary. The ownership of the SPS and PPS buffers 184 | * stays with the caller. It is the caller's responsibility to ensure that 185 | * the instance is configured to decode a H.264 stream. 186 | * @param self decoder instance handle 187 | * @param[in] sps: pointer to the SPS data 188 | * @param[in] sps_size: SPS size 189 | * @param[in] pps: pointer to the PPS data 190 | * @param[in] pps_size: PPS size 191 | * @param[in] format: SPS and PPS data format 192 | * @return 0 on success, negative errno value in case of error 193 | */ 194 | VDEC_API int vdec_set_h264_ps(struct vdec_decoder *self, 195 | const uint8_t *sps, 196 | size_t sps_size, 197 | const uint8_t *pps, 198 | size_t pps_size, 199 | const struct vdef_coded_format *format); 200 | 201 | 202 | /** 203 | * Set the H.265 parameter sets for decoding. 204 | * This function must be called prior to decoding (i.e. pushing buffers 205 | * into the input queue) with the H.265 VPS, SPS and 206 | * PPS. Ownership of buffers is retained by the caller. It is the caller's 207 | * responsibility to ensure that the instance is configured to decode a H.265 208 | * stream. 209 | * @param[in] self: decoder instance handle 210 | * @param[in] vps: VPS buffer pointer 211 | * @param[in] vps_size: VPS buffer size 212 | * @param[in] sps: SPS buffer pointer 213 | * @param[in] sps_size: SPS buffer size 214 | * @param[in] pps: PPS buffer pointer 215 | * @param[in] pps_size: PPS buffer size 216 | * @param[in] format: data format 217 | * @return 0 on success, negative errno value in case of error. 218 | */ 219 | VDEC_API int vdec_set_h265_ps(struct vdec_decoder *self, 220 | const uint8_t *vps, 221 | size_t vps_size, 222 | const uint8_t *sps, 223 | size_t sps_size, 224 | const uint8_t *pps, 225 | size_t pps_size, 226 | const struct vdef_coded_format *format); 227 | 228 | 229 | /** 230 | * Get the input buffer pool. 231 | * The input buffer pool is defined only for implementations that require 232 | * using input memories from the decoder's own pool. This function must 233 | * be called prior to decoding and if the returned value is not NULL the 234 | * input buffer pool should be used to get input memories. If the input 235 | * memories provided are not originating from the pool, they will be copied 236 | * resulting in a loss of performance. 237 | * @param self: decoder instance handle 238 | * @return a pointer on the input memory pool on success, NULL in case of 239 | * error or if no pool is used 240 | */ 241 | VDEC_API struct mbuf_pool * 242 | vdec_get_input_buffer_pool(struct vdec_decoder *self); 243 | 244 | 245 | /** 246 | * Get the input frame queue. 247 | * This function must be called prior to decoding and the input 248 | * frame queue must be used to push input frames for decoding. 249 | * @param self: decoder instance handle 250 | * @return a pointer on the input frame queue on success, NULL in case of error 251 | */ 252 | VDEC_API struct mbuf_coded_video_frame_queue * 253 | vdec_get_input_buffer_queue(struct vdec_decoder *self); 254 | 255 | 256 | /** 257 | * Get the video dimensions. 258 | * @param self: decoder instance handle 259 | * @param width: video width (output, optional, can be null) 260 | * @param height: video height (output, optional, can be null) 261 | * @param sar_width: video SAR width (output, optional, can be null) 262 | * @param sar_width: video SAR height (output, optional, can be null) 263 | * @param crop_left: video crop X coordinate (output, optional, can be null) 264 | * @param crop_top: video crop Y coordinate (output, optional, can be null) 265 | * @param crop_width: video crop width (output, optional, can be null) 266 | * @param crop_height: video crop height (output, optional, can be null) 267 | * @return 0 on success, negative errno value in case of error 268 | */ 269 | VDEC_API int vdec_get_video_dimensions(struct vdec_decoder *self, 270 | unsigned int *width, 271 | unsigned int *height, 272 | unsigned int *sar_width, 273 | unsigned int *sar_height, 274 | unsigned int *crop_left, 275 | unsigned int *crop_top, 276 | unsigned int *crop_width, 277 | unsigned int *crop_height); 278 | 279 | 280 | /** 281 | * Get the decoder implementation used. 282 | * @param self: decoder instance handle 283 | * @return the decoder implementation used, or VDEC_DECODER_IMPLEM_AUTO 284 | * in case of error 285 | */ 286 | VDEC_API enum vdec_decoder_implem 287 | vdec_get_used_implem(struct vdec_decoder *self); 288 | 289 | 290 | #ifdef __cplusplus 291 | } 292 | #endif /* __cplusplus */ 293 | 294 | #endif /* !_VDEC_H_ */ 295 | -------------------------------------------------------------------------------- /mediacodec/include/video-decode/vdec_mediacodec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_MEDIACODEC_H_ 28 | #define _VDEC_MEDIACODEC_H_ 29 | 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif /* __cplusplus */ 35 | 36 | /* To be used for all public API */ 37 | #ifdef VDEC_API_EXPORTS 38 | # ifdef _WIN32 39 | # define VDEC_API __declspec(dllexport) 40 | # else /* !_WIN32 */ 41 | # define VDEC_API __attribute__((visibility("default"))) 42 | # endif /* !_WIN32 */ 43 | #else /* !VDEC_API_EXPORTS */ 44 | # define VDEC_API 45 | #endif /* !VDEC_API_EXPORTS */ 46 | 47 | 48 | #define VDEC_MEDIACODEC_NB_SUPPORTED_FORMATS 2 49 | 50 | 51 | extern VDEC_API const struct vdec_ops vdec_mediacodec_ops; 52 | 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif /* __cplusplus */ 57 | 58 | 59 | #endif /* !_VDEC_MEDIACODEC_H_ */ 60 | -------------------------------------------------------------------------------- /mediacodec/src/vdec_mediacodec_convert.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | */ 4 | 5 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) 6 | 7 | 8 | static struct { 9 | media_status_t status; 10 | const char *status_str; 11 | } media_status_map[] = { 12 | {AMEDIA_OK, "OK"}, 13 | {AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE, 14 | "ERROR_INSUFFICIENT_RESOURCE"}, 15 | {AMEDIACODEC_ERROR_RECLAIMED, "ERROR_RECLAIMED"}, 16 | {AMEDIA_ERROR_BASE, "ERROR_BASE"}, 17 | {AMEDIA_ERROR_UNKNOWN, "ERROR_UNKNOWN"}, 18 | {AMEDIA_ERROR_MALFORMED, "ERROR_MALFORMED"}, 19 | {AMEDIA_ERROR_UNSUPPORTED, "ERROR_UNSUPPORTED"}, 20 | {AMEDIA_ERROR_INVALID_OBJECT, "ERROR_INVALID_OBJECT"}, 21 | {AMEDIA_ERROR_INVALID_PARAMETER, "ERROR_INVALID_PARAMETER"}, 22 | {AMEDIA_ERROR_INVALID_OPERATION, "ERROR_INVALID_OPERATION"}, 23 | {AMEDIA_ERROR_END_OF_STREAM, "ERROR_END_OF_STREAM"}, 24 | {AMEDIA_ERROR_IO, "ERROR_IO"}, 25 | {AMEDIA_ERROR_WOULD_BLOCK, "ERROR_WOULD_BLOCK"}, 26 | {AMEDIA_DRM_ERROR_BASE, "DRM_ERROR_BASE"}, 27 | {AMEDIA_DRM_NOT_PROVISIONED, "DRM_NOT_PROVISIONED"}, 28 | {AMEDIA_DRM_RESOURCE_BUSY, "DRM_RESOURCE_BUSY"}, 29 | {AMEDIA_DRM_DEVICE_REVOKED, "DRM_DEVICE_REVOKED"}, 30 | {AMEDIA_DRM_SHORT_BUFFER, "DRM_SHORT_BUFFER"}, 31 | {AMEDIA_DRM_SESSION_NOT_OPENED, "DRM_SESSION_NOT_OPENED"}, 32 | {AMEDIA_DRM_TAMPER_DETECTED, "DRM_TAMPER_DETECTED"}, 33 | {AMEDIA_DRM_VERIFY_FAILED, "DRM_VERIFY_FAILED"}, 34 | {AMEDIA_DRM_NEED_KEY, "DRM_NEED_KEY"}, 35 | {AMEDIA_DRM_LICENSE_EXPIRED, "DRM_LICENSE_EXPIRED"}, 36 | {AMEDIA_IMGREADER_ERROR_BASE, "IMGREADER_ERROR_BASE"}, 37 | {AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE, "IMGREADER_NO_BUFFER_AVAILABLE"}, 38 | {AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED, "IMGREADER_MAX_IMAGES_ACQUIRED"}, 39 | {AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE, "IMGREADER_CANNOT_LOCK_IMAGE"}, 40 | {AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE, "IMGREADER_CANNOT_UNLOCK_IMAGE"}, 41 | {AMEDIA_IMGREADER_IMAGE_NOT_LOCKED, "IMGREADER_IMAGE_NOT_LOCKED"}, 42 | }; 43 | 44 | 45 | static inline const char *media_status_to_str(media_status_t status) 46 | { 47 | unsigned int i; 48 | for (i = 0; i < ARRAY_SIZE(media_status_map); i++) { 49 | if (media_status_map[i].status == status) 50 | return media_status_map[i].status_str; 51 | } 52 | return "UNKNOWN"; 53 | } 54 | -------------------------------------------------------------------------------- /mediacodec/src/vdec_mediacodec_priv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_MEDIACODEC_PRIV_H_ 28 | #define _VDEC_MEDIACODEC_PRIV_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | 45 | #define VDEC_ANCILLARY_KEY_MEDIACODEC_PTS "vdec.mediacodec.pts" 46 | 47 | 48 | enum state { 49 | RUNNING, 50 | WAITING_FOR_STOP, 51 | WAITING_FOR_FLUSH, 52 | }; 53 | 54 | 55 | /* See 56 | * https://developer.android.com/reference/android/media/MediaCodecInfo.CodecCapabilities.html 57 | * for reference. */ 58 | enum color_format { 59 | YUV420_PLANAR = 0x00000013, 60 | YUV420_PACKED_PLANAR = 0x00000014, 61 | YUV420_SEMIPLANAR = 0x00000015, 62 | YUV420_PACKED_SEMIPLANAR = 0x00000027, 63 | TI_YUV420_PACKED_SEMIPLANAR = 0x7F000100, 64 | QCOM_YUV420_SEMIPLANAR = 0x7FA30C00, 65 | QCOM_YUV420_PACKED_SEMIPLANAR64X32_TILE2_M8KA = 0x7FA30C03, 66 | QCOM_YUV420_SEMIPLANAR32_M = 0x7FA30C04, 67 | }; 68 | 69 | 70 | struct vdec_mediacodec { 71 | struct vdec_decoder *base; 72 | 73 | AMediaCodec *mc; 74 | 75 | atomic_int state; 76 | 77 | struct mbuf_coded_video_frame_queue *in_queue; 78 | struct mbuf_coded_video_frame_queue *meta_queue; 79 | struct mbuf_raw_video_frame_queue *out_queue; 80 | struct mbuf_mem *mem; 81 | struct pomp_evt *out_evt; 82 | 83 | char *dec_name; 84 | 85 | struct { 86 | pthread_t thread; 87 | bool thread_created; 88 | pthread_mutex_t mutex; 89 | pthread_cond_t cond; 90 | bool cond_signalled; 91 | bool stop_requested; 92 | bool flush_requested; 93 | bool eos_requested; 94 | } push; 95 | 96 | struct { 97 | pthread_t thread; 98 | bool thread_created; 99 | pthread_mutex_t mutex; 100 | pthread_cond_t cond; 101 | bool cond_signalled; 102 | bool stop_requested; 103 | bool flush_requested; 104 | bool eos_requested; 105 | } pull; 106 | 107 | bool eos_requested; 108 | bool eos_pending; 109 | 110 | struct vdef_raw_format output_format; 111 | unsigned int stride; 112 | unsigned int slice_height; 113 | 114 | atomic_bool need_sync; 115 | }; 116 | 117 | 118 | /* Type conversion functions between Mediacodec & venc types */ 119 | #include "vdec_mediacodec_convert.h" 120 | 121 | #endif /* !_VDEC_MEDIACODEC_PRIV_H_ */ 122 | -------------------------------------------------------------------------------- /src/vdec.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define ULOG_TAG vdec 28 | #include "vdec_priv.h" 29 | ULOG_DECLARE_TAG(vdec); 30 | 31 | 32 | #ifndef VDEC_FFMPEG_NB_SUPPORTED_FORMATS 33 | # define VDEC_FFMPEG_NB_SUPPORTED_FORMATS 0 34 | #endif 35 | #ifndef VDEC_MEDIACODEC_NB_SUPPORTED_FORMATS 36 | # define VDEC_MEDIACODEC_NB_SUPPORTED_FORMATS 0 37 | #endif 38 | #ifndef VDEC_VIDEOTOOLBOX_NB_SUPPORTED_FORMATS 39 | # define VDEC_VIDEOTOOLBOX_NB_SUPPORTED_FORMATS 0 40 | #endif 41 | #ifndef VDEC_HISI_NB_SUPPORTED_FORMATS 42 | # define VDEC_HISI_NB_SUPPORTED_FORMATS 0 43 | #endif 44 | #ifndef VDEC_AML_NB_SUPPORTED_FORMATS 45 | # define VDEC_AML_NB_SUPPORTED_FORMATS 0 46 | #endif 47 | #ifndef VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS 48 | # define VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS 0 49 | #endif 50 | #ifndef VDEC_QCOM_NB_SUPPORTED_FORMATS 51 | # define VDEC_QCOM_NB_SUPPORTED_FORMATS 0 52 | #endif 53 | 54 | #define MAX_NB_SUPPORTED_FORMATS \ 55 | (VDEC_FFMPEG_NB_SUPPORTED_FORMATS + \ 56 | VDEC_MEDIACODEC_NB_SUPPORTED_FORMATS + \ 57 | VDEC_VIDEOTOOLBOX_NB_SUPPORTED_FORMATS + \ 58 | VDEC_HISI_NB_SUPPORTED_FORMATS + VDEC_AML_NB_SUPPORTED_FORMATS + \ 59 | VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS + VDEC_QCOM_NB_SUPPORTED_FORMATS) 60 | 61 | 62 | static atomic_int s_instance_counter; 63 | static pthread_once_t instance_counter_is_init = PTHREAD_ONCE_INIT; 64 | static void initialize_instance_counter(void) 65 | { 66 | atomic_init(&s_instance_counter, 0); 67 | } 68 | 69 | 70 | static unsigned int supported_format_count; 71 | static struct vdef_coded_format supported_formats[MAX_NB_SUPPORTED_FORMATS]; 72 | static pthread_once_t supported_formats_is_init = PTHREAD_ONCE_INIT; 73 | 74 | 75 | static void add_supported_formats(const struct vdef_coded_format *formats, 76 | int count) 77 | { 78 | for (int i = 0; i < count; i++) { 79 | bool found = false; 80 | #pragma GCC diagnostic push 81 | #pragma GCC diagnostic ignored "-Wunreachable-code" 82 | /* coverity[unreachable] */ 83 | for (unsigned int j = 0; j < supported_format_count; j++) { 84 | if (vdef_coded_format_cmp(&formats[i], 85 | &supported_formats[j])) 86 | found = true; 87 | break; 88 | } 89 | #pragma GCC diagnostic pop 90 | if (found) 91 | continue; 92 | supported_formats[supported_format_count++] = formats[i]; 93 | } 94 | } 95 | 96 | 97 | static void initialize_supported_formats(void) 98 | { 99 | int count VDEC_UNUSED; 100 | const struct vdef_coded_format *formats VDEC_UNUSED; 101 | 102 | supported_format_count = 0; 103 | #ifdef BUILD_LIBVIDEO_DECODE_FFMPEG 104 | count = vdec_ffmpeg_ops.get_supported_input_formats(&formats); 105 | add_supported_formats(formats, count); 106 | #endif 107 | #ifdef BUILD_LIBVIDEO_DECODE_MEDIACODEC 108 | count = vdec_mediacodec_ops.get_supported_input_formats(&formats); 109 | add_supported_formats(formats, count); 110 | #endif 111 | #ifdef BUILD_LIBVIDEO_DECODE_VIDEOTOOLBOX 112 | count = vdec_videotoolbox_ops.get_supported_input_formats(&formats); 113 | add_supported_formats(formats, count); 114 | #endif 115 | #ifdef BUILD_LIBVIDEO_DECODE_HISI 116 | count = vdec_hisi_ops.get_supported_input_formats(&formats); 117 | add_supported_formats(formats, count); 118 | #endif 119 | #ifdef BUILD_LIBVIDEO_DECODE_AML 120 | count = vdec_aml_ops.get_supported_input_formats(&formats); 121 | add_supported_formats(formats, count); 122 | #endif 123 | #ifdef BUILD_LIBVIDEO_DECODE_TURBOJPEG 124 | count = vdec_turbojpeg_ops.get_supported_input_formats(&formats); 125 | add_supported_formats(formats, count); 126 | #endif 127 | #ifdef BUILD_LIBVIDEO_DECODE_QCOM 128 | count = vdec_qcom_ops.get_supported_input_formats(&formats); 129 | add_supported_formats(formats, count); 130 | #endif 131 | } 132 | 133 | 134 | static const struct vdec_ops *implem_ops(enum vdec_decoder_implem implem) 135 | { 136 | switch (implem) { 137 | #ifdef BUILD_LIBVIDEO_DECODE_FFMPEG 138 | case VDEC_DECODER_IMPLEM_FFMPEG: 139 | return &vdec_ffmpeg_ops; 140 | #endif 141 | #ifdef BUILD_LIBVIDEO_DECODE_MEDIACODEC 142 | case VDEC_DECODER_IMPLEM_MEDIACODEC: 143 | return &vdec_mediacodec_ops; 144 | #endif 145 | #ifdef BUILD_LIBVIDEO_DECODE_VIDEOTOOLBOX 146 | case VDEC_DECODER_IMPLEM_VIDEOTOOLBOX: 147 | return &vdec_videotoolbox_ops; 148 | #endif 149 | #ifdef BUILD_LIBVIDEO_DECODE_HISI 150 | case VDEC_DECODER_IMPLEM_HISI: 151 | return &vdec_hisi_ops; 152 | #endif 153 | #ifdef BUILD_LIBVIDEO_DECODE_AML 154 | case VDEC_DECODER_IMPLEM_AML: 155 | return &vdec_aml_ops; 156 | #endif 157 | #ifdef BUILD_LIBVIDEO_DECODE_TURBOJPEG 158 | case VDEC_DECODER_IMPLEM_TURBOJPEG: 159 | return &vdec_turbojpeg_ops; 160 | #endif 161 | #ifdef BUILD_LIBVIDEO_DECODE_QCOM 162 | case VDEC_DECODER_IMPLEM_QCOM: 163 | return &vdec_qcom_ops; 164 | #endif 165 | default: 166 | return NULL; 167 | } 168 | } 169 | 170 | 171 | static int vdec_get_implem(enum vdec_decoder_implem *implem) 172 | { 173 | ULOG_ERRNO_RETURN_ERR_IF(implem == NULL, EINVAL); 174 | 175 | #ifdef BUILD_LIBVIDEO_DECODE_AML 176 | if ((*implem == VDEC_DECODER_IMPLEM_AUTO) || 177 | (*implem == VDEC_DECODER_IMPLEM_AML)) { 178 | *implem = VDEC_DECODER_IMPLEM_AML; 179 | return 0; 180 | } 181 | #endif /* BUILD_LIBVIDEO_DECODE_AML */ 182 | 183 | #ifdef BUILD_LIBVIDEO_DECODE_HISI 184 | if ((*implem == VDEC_DECODER_IMPLEM_AUTO) || 185 | (*implem == VDEC_DECODER_IMPLEM_HISI)) { 186 | *implem = VDEC_DECODER_IMPLEM_HISI; 187 | return 0; 188 | } 189 | #endif /* BUILD_LIBVIDEO_DECODE_HISI */ 190 | 191 | #ifdef BUILD_LIBVIDEO_DECODE_VIDEOTOOLBOX 192 | if ((*implem == VDEC_DECODER_IMPLEM_AUTO) || 193 | (*implem == VDEC_DECODER_IMPLEM_VIDEOTOOLBOX)) { 194 | *implem = VDEC_DECODER_IMPLEM_VIDEOTOOLBOX; 195 | return 0; 196 | } 197 | #endif /* BUILD_LIBVIDEO_DECODE_VIDEOTOOLBOX */ 198 | 199 | #ifdef BUILD_LIBVIDEO_DECODE_MEDIACODEC 200 | if ((*implem == VDEC_DECODER_IMPLEM_AUTO) || 201 | (*implem == VDEC_DECODER_IMPLEM_MEDIACODEC)) { 202 | *implem = VDEC_DECODER_IMPLEM_MEDIACODEC; 203 | return 0; 204 | } 205 | #endif /* BUILD_LIBVIDEO_DECODE_MEDIACODEC */ 206 | 207 | #ifdef BUILD_LIBVIDEO_DECODE_FFMPEG 208 | if ((*implem == VDEC_DECODER_IMPLEM_AUTO) || 209 | (*implem == VDEC_DECODER_IMPLEM_FFMPEG)) { 210 | *implem = VDEC_DECODER_IMPLEM_FFMPEG; 211 | return 0; 212 | } 213 | #endif /* BUILD_LIBVIDEO_DECODE_FFMPEG */ 214 | 215 | #ifdef BUILD_LIBVIDEO_DECODE_TURBOJPEG 216 | if ((*implem == VDEC_DECODER_IMPLEM_AUTO) || 217 | (*implem == VDEC_DECODER_IMPLEM_TURBOJPEG)) { 218 | *implem = VDEC_DECODER_IMPLEM_TURBOJPEG; 219 | return 0; 220 | } 221 | #endif /* BUILD_LIBVIDEO_DECODE_TURBOJPEG */ 222 | 223 | #ifdef BUILD_LIBVIDEO_DECODE_QCOM 224 | if ((*implem == VDEC_DECODER_IMPLEM_AUTO) || 225 | (*implem == VDEC_DECODER_IMPLEM_QCOM)) { 226 | *implem = VDEC_DECODER_IMPLEM_QCOM; 227 | return 0; 228 | } 229 | #endif /* BUILD_LIBVIDEO_DECODE_QCOM */ 230 | 231 | return -ENOSYS; 232 | } 233 | 234 | 235 | static void 236 | log_video_info(struct vdec_decoder *self, struct video_info *info, int level) 237 | { 238 | /* Log photo/video info */ 239 | VDEC_LOG_INT(level, 240 | "dimensions: width=%u height=%u SAR=%u:%u", 241 | info->resolution.width, 242 | info->resolution.height, 243 | info->sar.width, 244 | info->sar.height); 245 | VDEC_LOG_INT(level, 246 | "crop: left=%u top=%u width=%u height=%u", 247 | info->crop.left, 248 | info->crop.top, 249 | info->crop.width, 250 | info->crop.height); 251 | if ((info->framerate.num != 0) && (info->framerate.den != 0)) { 252 | VDEC_LOG_INT(level, 253 | "declared framerate: %u/%u -> %.3f fps", 254 | info->framerate.num, 255 | info->framerate.den, 256 | (float)info->framerate.num / 257 | (float)info->framerate.den); 258 | } 259 | VDEC_LOG_INT(level, 260 | "%d bits, color primaries: %s, transfer function: %s, " 261 | "matrix coefficients: %s, full range: %d", 262 | info->bit_depth, 263 | vdef_color_primaries_to_str(info->color_primaries), 264 | vdef_transfer_function_to_str(info->transfer_function), 265 | vdef_matrix_coefs_to_str(info->matrix_coefs), 266 | info->full_range); 267 | if ((info->nal_hrd_bitrate != 0) && (info->nal_hrd_cpb_size != 0)) { 268 | VDEC_LOG_INT(level, 269 | "declared NAL bitrate: " 270 | "%u bit/s (CPB size %u bits)", 271 | info->nal_hrd_bitrate, 272 | info->nal_hrd_cpb_size); 273 | } 274 | if ((info->vcl_hrd_bitrate != 0) && (info->vcl_hrd_cpb_size != 0)) { 275 | VDEC_LOG_INT(level, 276 | "declared VCL bitrate: " 277 | "%u bit/s (CPB size %u bits)", 278 | info->vcl_hrd_bitrate, 279 | info->vcl_hrd_cpb_size); 280 | } 281 | } 282 | 283 | 284 | int vdec_get_supported_input_formats(enum vdec_decoder_implem implem, 285 | const struct vdef_coded_format **formats) 286 | { 287 | int ret; 288 | ULOG_ERRNO_RETURN_ERR_IF(!formats, EINVAL); 289 | 290 | ret = vdec_get_implem(&implem); 291 | if (ret < 0) { 292 | ULOG_ERRNO("vdec_get_implem", -ret); 293 | return ret; 294 | } 295 | 296 | return implem_ops(implem)->get_supported_input_formats(formats); 297 | } 298 | 299 | 300 | int vdec_get_all_supported_input_formats( 301 | const struct vdef_coded_format **formats) 302 | { 303 | ULOG_ERRNO_RETURN_ERR_IF(!formats, EINVAL); 304 | 305 | (void)pthread_once(&supported_formats_is_init, 306 | initialize_supported_formats); 307 | *formats = supported_formats; 308 | return supported_format_count; 309 | } 310 | 311 | 312 | enum vdec_decoder_implem vdec_get_auto_implem(void) 313 | { 314 | int ret; 315 | enum vdec_decoder_implem implem = VDEC_DECODER_IMPLEM_AUTO; 316 | 317 | ret = vdec_get_implem(&implem); 318 | ULOG_ERRNO_RETURN_VAL_IF(ret < 0, -ret, VDEC_DECODER_IMPLEM_AUTO); 319 | 320 | return implem; 321 | } 322 | 323 | 324 | enum vdec_decoder_implem 325 | vdec_get_auto_implem_by_coded_format(struct vdef_coded_format *format) 326 | { 327 | int res = 0, count; 328 | const struct vdef_coded_format *supported_input_formats; 329 | 330 | ULOG_ERRNO_RETURN_VAL_IF( 331 | format == NULL, EINVAL, VDEC_DECODER_IMPLEM_AUTO); 332 | 333 | for (enum vdec_decoder_implem implem = VDEC_DECODER_IMPLEM_AUTO + 1; 334 | implem < VDEC_DECODER_IMPLEM_MAX; 335 | implem++) { 336 | 337 | res = vdec_get_implem(&implem); 338 | if (res < 0) 339 | continue; 340 | 341 | count = implem_ops(implem)->get_supported_input_formats( 342 | &supported_input_formats); 343 | if (count < 0) 344 | continue; 345 | 346 | if (!vdef_coded_format_intersect( 347 | format, supported_input_formats, count)) 348 | continue; 349 | 350 | return implem; 351 | } 352 | 353 | return VDEC_DECODER_IMPLEM_AUTO; 354 | } 355 | 356 | 357 | static void h264_nalu_begin_cb(struct h264_ctx *ctx, 358 | enum h264_nalu_type type, 359 | const uint8_t *buf, 360 | size_t len, 361 | const struct h264_nalu_header *nh, 362 | void *userdata) 363 | { 364 | struct vdec_decoder *self = userdata; 365 | 366 | VDEC_LOG_ERRNO_RETURN_IF(self == NULL, EINVAL); 367 | VDEC_LOG_ERRNO_RETURN_IF(ctx == NULL, EINVAL); 368 | VDEC_LOG_ERRNO_RETURN_IF(buf == NULL, EINVAL); 369 | VDEC_LOG_ERRNO_RETURN_IF(len == 0, EINVAL); 370 | 371 | vdec_dbg_h264_nalu_begin(self, *nh, type); 372 | } 373 | 374 | 375 | static void h264_slice_cb(struct h264_ctx *ctx, 376 | const uint8_t *buf, 377 | size_t len, 378 | const struct h264_slice_header *sh, 379 | void *userdata) 380 | { 381 | struct vdec_decoder *self = userdata; 382 | struct h264_nalu_header nh; 383 | int res; 384 | 385 | VDEC_LOG_ERRNO_RETURN_IF(self == NULL, EINVAL); 386 | VDEC_LOG_ERRNO_RETURN_IF(ctx == NULL, EINVAL); 387 | VDEC_LOG_ERRNO_RETURN_IF(buf == NULL, EINVAL); 388 | VDEC_LOG_ERRNO_RETURN_IF(len == 0, EINVAL); 389 | VDEC_LOG_ERRNO_RETURN_IF(sh == NULL, EINVAL); 390 | 391 | res = h264_parse_nalu_header(buf, len, &nh); 392 | if (res < 0) { 393 | VDEC_LOG_ERRNO("h264_parse_nalu_header", -res); 394 | return; 395 | } 396 | vdec_dbg_h264_slice(self, nh, sh); 397 | } 398 | 399 | 400 | static const struct h264_ctx_cbs h264_cbs = { 401 | .nalu_begin = h264_nalu_begin_cb, 402 | .slice = h264_slice_cb, 403 | }; 404 | 405 | 406 | static void h265_nalu_begin_cb(struct h265_ctx *ctx, 407 | enum h265_nalu_type type, 408 | const uint8_t *buf, 409 | size_t len, 410 | const struct h265_nalu_header *nh, 411 | void *userdata) 412 | { 413 | struct vdec_decoder *self = userdata; 414 | 415 | VDEC_LOG_ERRNO_RETURN_IF(self == NULL, EINVAL); 416 | VDEC_LOG_ERRNO_RETURN_IF(ctx == NULL, EINVAL); 417 | VDEC_LOG_ERRNO_RETURN_IF(buf == NULL, EINVAL); 418 | VDEC_LOG_ERRNO_RETURN_IF(len == 0, EINVAL); 419 | VDEC_LOG_ERRNO_RETURN_IF(nh == NULL, EINVAL); 420 | 421 | vdec_dbg_h265_nalu_begin(self, type); 422 | } 423 | 424 | 425 | static const struct h265_ctx_cbs h265_cbs = { 426 | .nalu_begin = h265_nalu_begin_cb, 427 | }; 428 | 429 | 430 | int vdec_new(struct pomp_loop *loop, 431 | const struct vdec_config *config, 432 | const struct vdec_cbs *cbs, 433 | void *userdata, 434 | struct vdec_decoder **ret_obj) 435 | { 436 | int ret, dbgret; 437 | struct vdec_decoder *self = NULL; 438 | const char *env_low_delay; 439 | const char *env_preferred_thread_count; 440 | const char *env_dbg_dir; 441 | const char *env_dbg_flags; 442 | 443 | VDEC_LOG_ERRNO_RETURN_ERR_IF(loop == NULL, EINVAL); 444 | VDEC_LOG_ERRNO_RETURN_ERR_IF(config == NULL, EINVAL); 445 | VDEC_LOG_ERRNO_RETURN_ERR_IF(cbs == NULL, EINVAL); 446 | VDEC_LOG_ERRNO_RETURN_ERR_IF(cbs->frame_output == NULL, EINVAL); 447 | VDEC_LOG_ERRNO_RETURN_ERR_IF(ret_obj == NULL, EINVAL); 448 | 449 | (void)pthread_once(&instance_counter_is_init, 450 | initialize_instance_counter); 451 | 452 | env_low_delay = getenv("VDEC_LOW_DELAY"); 453 | env_preferred_thread_count = getenv("VDEC_PREFERRED_THREAD_COUNT"); 454 | env_dbg_dir = getenv("VDEC_DBG_DIR"); 455 | env_dbg_flags = getenv("VDEC_DBG_FLAGS"); 456 | 457 | self = calloc(1, sizeof(*self)); 458 | if (self == NULL) 459 | return -ENOMEM; 460 | 461 | self->base = self; /* For logging */ 462 | self->loop = loop; 463 | self->cbs = *cbs; 464 | self->userdata = userdata; 465 | self->config = *config; 466 | self->config.name = xstrdup(config->name); 467 | atomic_init(&self->last_timestamp, UINT64_MAX); 468 | atomic_init(&self->counters.in, 0); 469 | atomic_init(&self->counters.out, 0); 470 | atomic_init(&self->counters.pulled, 0); 471 | atomic_init(&self->counters.pushed, 0); 472 | self->dec_id = (atomic_fetch_add(&s_instance_counter, 1) + 1); 473 | 474 | if (self->config.name != NULL) 475 | ret = asprintf(&self->dec_name, "%s", self->config.name); 476 | else 477 | ret = asprintf(&self->dec_name, "%02d", self->dec_id); 478 | if (ret < 0) { 479 | ret = -ENOMEM; 480 | VDEC_LOG_ERRNO("asprintf", -ret); 481 | goto error; 482 | } 483 | 484 | /* Override debug config with environment if set */ 485 | if (env_low_delay != NULL) 486 | self->config.low_delay = strtol(env_low_delay, NULL, 0); 487 | if (env_preferred_thread_count != NULL) { 488 | self->config.preferred_thread_count = 489 | strtol(env_preferred_thread_count, NULL, 0); 490 | } 491 | if (env_dbg_dir != NULL) 492 | self->config.dbg_dir = strdup(env_dbg_dir); 493 | else 494 | self->config.dbg_dir = xstrdup(config->dbg_dir); 495 | if (env_dbg_flags != NULL) 496 | self->config.dbg_flags = strtol(env_dbg_flags, NULL, 0); 497 | 498 | ret = vdec_get_implem(&self->config.implem); 499 | if (ret < 0) 500 | goto error; 501 | 502 | self->video_info.sar.width = 1; 503 | self->video_info.sar.height = 1; 504 | self->ops = implem_ops(self->config.implem); 505 | 506 | ret = self->ops->create(self); 507 | if (ret < 0) 508 | goto error; 509 | 510 | switch (self->config.encoding) { 511 | case VDEF_ENCODING_H264: 512 | ret = h264_reader_new(&h264_cbs, self, &self->reader.h264); 513 | if (ret < 0) 514 | VDEC_LOG_ERRNO("h264_reader_new", -ret); 515 | break; 516 | 517 | case VDEF_ENCODING_H265: 518 | ret = h265_reader_new(&h265_cbs, self, &self->reader.h265); 519 | if (ret < 0) 520 | VDEC_LOG_ERRNO("h265_reader_new", -ret); 521 | break; 522 | default: 523 | break; 524 | } 525 | 526 | if (self->config.dbg_dir != NULL) { 527 | dbgret = vdec_dbg_create_files(self); 528 | if (dbgret < 0) 529 | VDEC_LOG_ERRNO("vdec_dbg_create_files", -dbgret); 530 | } 531 | 532 | *ret_obj = self; 533 | return 0; 534 | 535 | error: 536 | vdec_destroy(self); 537 | *ret_obj = NULL; 538 | return ret; 539 | } 540 | 541 | 542 | int vdec_flush(struct vdec_decoder *self, int discard) 543 | { 544 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 545 | 546 | return self->ops->flush(self, discard); 547 | } 548 | 549 | 550 | int vdec_stop(struct vdec_decoder *self) 551 | { 552 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 553 | 554 | return self->ops->stop(self); 555 | } 556 | 557 | 558 | int vdec_destroy(struct vdec_decoder *self) 559 | { 560 | int ret = 0, dbgret; 561 | 562 | if (self == NULL) 563 | return 0; 564 | 565 | switch (self->config.encoding) { 566 | case VDEF_ENCODING_H264: 567 | if (self->reader.h264 != NULL) { 568 | ret = h264_reader_destroy(self->reader.h264); 569 | if (ret < 0) 570 | VDEC_LOG_ERRNO("h264_reader_destroy", -ret); 571 | } 572 | break; 573 | 574 | case VDEF_ENCODING_H265: 575 | if (self->reader.h265 != NULL) { 576 | ret = h265_reader_destroy(self->reader.h265); 577 | if (ret < 0) 578 | VDEC_LOG_ERRNO("h265_reader_destroy", -ret); 579 | } 580 | break; 581 | default: 582 | break; 583 | } 584 | 585 | 586 | if (self->ops) 587 | ret = self->ops->destroy(self); 588 | 589 | VDEC_LOGI("vdec instance stats: [%u [%u %u] %u]", 590 | self->counters.in, 591 | self->counters.pushed, 592 | self->counters.pulled, 593 | self->counters.out); 594 | 595 | if (ret == 0) { 596 | dbgret = vdec_dbg_close_files(self); 597 | if (dbgret < 0) 598 | VDEC_LOG_ERRNO("vdec_dbg_close_files", -dbgret); 599 | xfree((void **)&self->config.name); 600 | xfree((void **)&self->config.dbg_dir); 601 | xfree((void **)&self->dec_name); 602 | free(self); 603 | } 604 | 605 | return ret; 606 | } 607 | 608 | 609 | int vdec_set_jpeg_params(struct vdec_decoder *self, 610 | const struct vdef_format_info *format_info) 611 | { 612 | int ret = 0, count; 613 | const struct vdef_coded_format *supported_input_formats; 614 | 615 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 616 | VDEC_LOG_ERRNO_RETURN_ERR_IF(format_info == NULL, EINVAL); 617 | VDEC_LOG_ERRNO_RETURN_ERR_IF( 618 | (format_info->resolution.width == 0) || 619 | (format_info->resolution.height == 0), 620 | EINVAL); 621 | VDEC_LOG_ERRNO_RETURN_ERR_IF((format_info->framerate.num == 0) || 622 | (format_info->framerate.den == 0), 623 | EINVAL); 624 | VDEC_LOG_ERRNO_RETURN_ERR_IF( 625 | self->config.encoding != VDEF_ENCODING_MJPEG, EINVAL); 626 | 627 | count = self->ops->get_supported_input_formats( 628 | &supported_input_formats); 629 | if (count < 0) { 630 | VDEC_LOG_ERRNO("get_supported_input_formats", -count); 631 | return -EINVAL; 632 | } 633 | 634 | if (!vdef_coded_format_intersect( 635 | &vdef_jpeg_jfif, supported_input_formats, count)) { 636 | VDEC_LOG_ERRNO("unsupported input formats", EINVAL); 637 | return -EINVAL; 638 | } 639 | 640 | self->video_info = (const struct video_info){ 641 | .resolution = {format_info->resolution.width, 642 | format_info->resolution.height}, 643 | .bit_depth = format_info->bit_depth, 644 | .sar = format_info->sar, 645 | .crop = {0, 646 | 0, 647 | format_info->resolution.width, 648 | format_info->resolution.height}, 649 | .full_range = format_info->full_range, 650 | .color_primaries = format_info->color_primaries, 651 | .transfer_function = format_info->transfer_function, 652 | .matrix_coefs = format_info->matrix_coefs, 653 | .framerate.num = format_info->framerate.num, 654 | .framerate.den = format_info->framerate.den, 655 | }; 656 | 657 | if ((self->video_info.bit_depth != 8) || 658 | (self->video_info.color_primaries != VDEF_COLOR_PRIMARIES_SRGB) || 659 | (self->video_info.transfer_function != 660 | VDEF_TRANSFER_FUNCTION_BT709) || 661 | (self->video_info.matrix_coefs != VDEF_MATRIX_COEFS_BT709)) { 662 | VDEC_LOG_ERRNO("invalid input format", EINVAL); 663 | log_video_info(self, &self->video_info, ULOG_ERR); 664 | return -EINVAL; 665 | } 666 | 667 | log_video_info(self, &self->video_info, ULOG_INFO); 668 | 669 | if (!self->ops->set_jpeg_params) { 670 | self->configured = 1; 671 | return 0; 672 | } 673 | 674 | ret = self->ops->set_jpeg_params(self); 675 | self->configured = (ret == 0) ? 1 : 0; 676 | return ret; 677 | } 678 | 679 | 680 | int vdec_set_h264_ps(struct vdec_decoder *self, 681 | const uint8_t *sps, 682 | size_t sps_size, 683 | const uint8_t *pps, 684 | size_t pps_size, 685 | const struct vdef_coded_format *format) 686 | { 687 | int ret, count; 688 | 689 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 690 | VDEC_LOG_ERRNO_RETURN_ERR_IF(format == NULL, EINVAL); 691 | VDEC_LOG_ERRNO_RETURN_ERR_IF(format->encoding != self->config.encoding, 692 | EINVAL); 693 | VDEC_LOG_ERRNO_RETURN_ERR_IF(format->encoding != VDEF_ENCODING_H264, 694 | EINVAL); 695 | 696 | size_t offset = (format->data_format == VDEF_CODED_DATA_FORMAT_RAW_NALU) 697 | ? 0 698 | : 4; 699 | size_t size = 0, off = 0; 700 | uint8_t start_code[] = {0, 0, 0, 1}; 701 | struct h264_info info = {0}; 702 | struct h264_ctx *ctx = h264_reader_get_ctx(self->reader.h264); 703 | const struct vdef_coded_format *supported_input_formats; 704 | uint32_t sc; 705 | 706 | VDEC_LOG_ERRNO_RETURN_ERR_IF((sps == NULL) || (sps_size <= offset), 707 | EINVAL); 708 | VDEC_LOG_ERRNO_RETURN_ERR_IF((pps == NULL) || (pps_size <= offset), 709 | EINVAL); 710 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self->configured, EALREADY); 711 | 712 | /* SPS and PPS parsing */ 713 | size = 4 + sps_size - offset + 4 + pps_size - offset; 714 | 715 | uint8_t *data = malloc(size); 716 | if (data == NULL) 717 | return -ENOMEM; 718 | 719 | memcpy(&data[off], start_code, sizeof(start_code)); 720 | off += 4; 721 | memcpy(&data[off], &sps[offset], sps_size - offset); 722 | off += sps_size - offset; 723 | 724 | memcpy(&data[off], start_code, sizeof(start_code)); 725 | off += 4; 726 | memcpy(&data[off], &pps[offset], pps_size - offset); 727 | 728 | ret = h264_reader_parse(self->reader.h264, 0, data, size, &off); 729 | if (ret < 0) { 730 | VDEC_LOG_ERRNO("h264_reader_parse", -ret); 731 | goto out; 732 | } 733 | 734 | /* Get the video info */ 735 | ret = h264_ctx_get_info(ctx, &info); 736 | if (ret < 0) { 737 | VDEC_LOG_ERRNO("h264_ctx_get_info", -ret); 738 | goto out; 739 | } 740 | 741 | self->video_info = (const struct video_info){ 742 | .resolution = {info.width, info.height}, 743 | .bit_depth = info.bit_depth_luma, 744 | .sar = {info.sar_width, info.sar_height}, 745 | .crop = {info.crop_left, 746 | info.crop_top, 747 | info.crop_width, 748 | info.crop_height}, 749 | .full_range = info.full_range, 750 | .color_primaries = 751 | vdef_color_primaries_from_h264(info.colour_primaries), 752 | .transfer_function = vdef_transfer_function_from_h264( 753 | info.transfer_characteristics), 754 | .matrix_coefs = 755 | vdef_matrix_coefs_from_h264(info.matrix_coefficients), 756 | .framerate.num = info.framerate_num, 757 | .framerate.den = info.framerate_den, 758 | .nal_hrd_bitrate = info.nal_hrd_bitrate, 759 | .nal_hrd_cpb_size = info.nal_hrd_cpb_size, 760 | .vcl_hrd_bitrate = info.vcl_hrd_bitrate, 761 | .vcl_hrd_cpb_size = info.vcl_hrd_cpb_size, 762 | }; 763 | 764 | log_video_info(self, &self->video_info, ULOG_INFO); 765 | 766 | count = self->ops->get_supported_input_formats( 767 | &supported_input_formats); 768 | if (count < 0) { 769 | VDEC_LOG_ERRNO("get_supported_input_formats", -count); 770 | goto out; 771 | } 772 | 773 | if (self->ops->set_h264_ps) { 774 | if (vdef_coded_format_intersect( 775 | format, supported_input_formats, count)) { 776 | ret = self->ops->set_h264_ps( 777 | self, sps, sps_size, pps, pps_size, format); 778 | } else { 779 | if (vdef_coded_format_intersect(&vdef_h264_raw_nalu, 780 | supported_input_formats, 781 | count)) { 782 | ret = self->ops->set_h264_ps( 783 | self, 784 | &data[4], 785 | sps_size - offset, 786 | &data[8 + sps_size - offset], 787 | pps_size - offset, 788 | &vdef_h264_raw_nalu); 789 | } else if (vdef_coded_format_intersect( 790 | &vdef_h264_byte_stream, 791 | supported_input_formats, 792 | count)) { 793 | ret = self->ops->set_h264_ps( 794 | self, 795 | data, 796 | 4 + sps_size - offset, 797 | &data[4 + sps_size - offset], 798 | 4 + pps_size - offset, 799 | &vdef_h264_byte_stream); 800 | } else if (vdef_coded_format_intersect( 801 | &vdef_h264_avcc, 802 | supported_input_formats, 803 | count)) { 804 | sc = htonl(sps_size - offset); 805 | memcpy(data, &sc, sizeof(sc)); 806 | sc = htonl(pps_size - offset); 807 | memcpy(&data[4 + sps_size - offset], 808 | &sc, 809 | sizeof(sc)); 810 | ret = self->ops->set_h264_ps( 811 | self, 812 | data, 813 | 4 + sps_size - offset, 814 | &data[4 + sps_size - offset], 815 | 4 + pps_size - offset, 816 | &vdef_h264_avcc); 817 | } else { 818 | ret = -ENOSYS; 819 | VDEC_LOG_ERRNO( 820 | "unsupported format:" 821 | " " VDEF_CODED_FORMAT_TO_STR_FMT, 822 | -ret, 823 | VDEF_CODED_FORMAT_TO_STR_ARG(format)); 824 | } 825 | } 826 | } else { 827 | ret = -ENOSYS; 828 | } 829 | 830 | 831 | self->configured = (ret == 0) ? 1 : 0; 832 | 833 | /* Debug files */ 834 | if (self->dbg.input_bs != NULL) { 835 | int dbgret = vdec_dbg_write_h264_ps(self->dbg.input_bs, 836 | sps, 837 | sps_size, 838 | pps, 839 | pps_size, 840 | format); 841 | if (dbgret < 0) 842 | VDEC_LOG_ERRNO("vdec_dbg_write_h264_ps", -dbgret); 843 | } 844 | 845 | out: 846 | if (data) 847 | free(data); 848 | return ret; 849 | } 850 | 851 | 852 | int vdec_set_h265_ps(struct vdec_decoder *self, 853 | const uint8_t *vps, 854 | size_t vps_size, 855 | const uint8_t *sps, 856 | size_t sps_size, 857 | const uint8_t *pps, 858 | size_t pps_size, 859 | const struct vdef_coded_format *format) 860 | { 861 | int ret, count; 862 | 863 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 864 | VDEC_LOG_ERRNO_RETURN_ERR_IF(format == NULL, EINVAL); 865 | VDEC_LOG_ERRNO_RETURN_ERR_IF(format->encoding != self->config.encoding, 866 | EINVAL); 867 | VDEC_LOG_ERRNO_RETURN_ERR_IF(format->encoding != VDEF_ENCODING_H265, 868 | EINVAL); 869 | 870 | size_t offset = (format->data_format == VDEF_CODED_DATA_FORMAT_RAW_NALU) 871 | ? 0 872 | : 4; 873 | size_t size = 0, off = 0; 874 | uint8_t start_code[] = {0, 0, 0, 1}; 875 | struct h265_info info = {0}; 876 | struct h265_ctx *ctx = h265_reader_get_ctx(self->reader.h265); 877 | const struct vdef_coded_format *supported_input_formats; 878 | uint32_t sc; 879 | 880 | VDEC_LOG_ERRNO_RETURN_ERR_IF((vps == NULL) || (vps_size <= offset), 881 | EINVAL); 882 | VDEC_LOG_ERRNO_RETURN_ERR_IF((sps == NULL) || (sps_size <= offset), 883 | EINVAL); 884 | VDEC_LOG_ERRNO_RETURN_ERR_IF((pps == NULL) || (pps_size <= offset), 885 | EINVAL); 886 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self->configured, EALREADY); 887 | 888 | /* VPS, SPS and PPS parsing */ 889 | size = 4 + vps_size - offset + 4 + sps_size - offset + 4 + pps_size - 890 | offset; 891 | 892 | uint8_t *data = malloc(size); 893 | if (data == NULL) 894 | return -ENOMEM; 895 | 896 | memcpy(&data[off], start_code, sizeof(start_code)); 897 | off += 4; 898 | memcpy(&data[off], &vps[offset], vps_size - offset); 899 | off += vps_size - offset; 900 | 901 | memcpy(&data[off], start_code, sizeof(start_code)); 902 | off += 4; 903 | memcpy(&data[off], &sps[offset], sps_size - offset); 904 | off += sps_size - offset; 905 | 906 | memcpy(&data[off], start_code, sizeof(start_code)); 907 | off += 4; 908 | memcpy(&data[off], &pps[offset], pps_size - offset); 909 | 910 | ret = h265_reader_parse(self->reader.h265, 0, data, size, &off); 911 | if (ret < 0) { 912 | VDEC_LOG_ERRNO("h265_reader_parse", -ret); 913 | goto out; 914 | } 915 | 916 | /* Get the video info */ 917 | ret = h265_ctx_get_info(ctx, &info); 918 | if (ret < 0) { 919 | VDEC_LOG_ERRNO("h264_ctx_get_info", -ret); 920 | goto out; 921 | } 922 | 923 | self->video_info = (const struct video_info){ 924 | .resolution = {info.width, info.height}, 925 | .bit_depth = info.bit_depth_luma, 926 | .sar = {info.sar_width, info.sar_height}, 927 | .crop = {info.crop_left, 928 | info.crop_top, 929 | info.crop_width, 930 | info.crop_height}, 931 | .full_range = info.full_range, 932 | .color_primaries = 933 | vdef_color_primaries_from_h265(info.colour_primaries), 934 | .transfer_function = vdef_transfer_function_from_h265( 935 | info.transfer_characteristics), 936 | .matrix_coefs = 937 | vdef_matrix_coefs_from_h265(info.matrix_coefficients), 938 | .framerate.num = info.framerate_num, 939 | .framerate.den = info.framerate_den, 940 | .nal_hrd_bitrate = info.nal_hrd_bitrate, 941 | .nal_hrd_cpb_size = info.nal_hrd_cpb_size, 942 | .vcl_hrd_bitrate = info.vcl_hrd_bitrate, 943 | .vcl_hrd_cpb_size = info.vcl_hrd_cpb_size, 944 | }; 945 | 946 | log_video_info(self, &self->video_info, ULOG_INFO); 947 | 948 | if (self->ops->set_h265_ps) { 949 | count = self->ops->get_supported_input_formats( 950 | &supported_input_formats); 951 | if (count < 0) { 952 | VDEC_LOG_ERRNO("get_supported_input_formats", -count); 953 | goto out; 954 | } 955 | 956 | if (vdef_coded_format_intersect( 957 | format, supported_input_formats, count)) 958 | ret = self->ops->set_h265_ps(self, 959 | vps, 960 | vps_size, 961 | sps, 962 | sps_size, 963 | pps, 964 | pps_size, 965 | format); 966 | else { 967 | if (vdef_coded_format_intersect(&vdef_h265_raw_nalu, 968 | supported_input_formats, 969 | count)) 970 | ret = self->ops->set_h265_ps( 971 | self, 972 | &data[4], 973 | vps_size - offset, 974 | &data[8 + vps_size - offset], 975 | sps_size - offset, 976 | &data[12 + vps_size - offset + 977 | sps_size - offset], 978 | pps_size - offset, 979 | &vdef_h265_raw_nalu); 980 | else if (vdef_coded_format_intersect( 981 | &vdef_h265_byte_stream, 982 | supported_input_formats, 983 | count)) 984 | ret = self->ops->set_h265_ps( 985 | self, 986 | data, 987 | 4 + vps_size - offset, 988 | &data[4 + vps_size - offset], 989 | 4 + sps_size - offset, 990 | &data[8 + vps_size - offset + sps_size - 991 | offset], 992 | 4 + pps_size - offset, 993 | &vdef_h265_byte_stream); 994 | else if (vdef_coded_format_intersect( 995 | &vdef_h265_hvcc, 996 | supported_input_formats, 997 | count)) { 998 | sc = htonl(vps_size - offset); 999 | memcpy(data, &sc, sizeof(sc)); 1000 | sc = htonl(sps_size - offset); 1001 | memcpy(&data[4 + vps_size - offset], 1002 | &sc, 1003 | sizeof(sc)); 1004 | sc = htonl(pps_size - offset); 1005 | memcpy(&data[8 + vps_size - offset + sps_size - 1006 | offset], 1007 | &sc, 1008 | sizeof(sc)); 1009 | ret = self->ops->set_h265_ps( 1010 | self, 1011 | data, 1012 | 4 + vps_size - offset, 1013 | &data[4 + vps_size - offset], 1014 | 4 + sps_size - offset, 1015 | &data[8 + vps_size - offset + sps_size - 1016 | offset], 1017 | 4 + pps_size - offset, 1018 | &vdef_h265_hvcc); 1019 | } else { 1020 | ret = -ENOSYS; 1021 | VDEC_LOG_ERRNO( 1022 | "unsupported format:" 1023 | " " VDEF_CODED_FORMAT_TO_STR_FMT, 1024 | -ret, 1025 | VDEF_CODED_FORMAT_TO_STR_ARG(format)); 1026 | } 1027 | } 1028 | } else { 1029 | ret = -ENOSYS; 1030 | } 1031 | 1032 | self->configured = (ret == 0) ? 1 : 0; 1033 | 1034 | /* Debug files */ 1035 | if (self->dbg.input_bs != NULL) { 1036 | int dbgret = vdec_dbg_write_h265_ps(self->dbg.input_bs, 1037 | vps, 1038 | vps_size, 1039 | sps, 1040 | sps_size, 1041 | pps, 1042 | pps_size, 1043 | format); 1044 | if (dbgret < 0) 1045 | VDEC_LOG_ERRNO("vdec_dbg_write_h264_ps", -dbgret); 1046 | } 1047 | 1048 | out: 1049 | if (data) 1050 | free(data); 1051 | return ret; 1052 | } 1053 | 1054 | 1055 | struct mbuf_pool *vdec_get_input_buffer_pool(struct vdec_decoder *self) 1056 | { 1057 | VDEC_LOG_ERRNO_RETURN_VAL_IF(self == NULL, EINVAL, NULL); 1058 | 1059 | return self->ops->get_input_buffer_pool(self); 1060 | } 1061 | 1062 | 1063 | struct mbuf_coded_video_frame_queue * 1064 | vdec_get_input_buffer_queue(struct vdec_decoder *self) 1065 | { 1066 | VDEC_LOG_ERRNO_RETURN_VAL_IF(self == NULL, EINVAL, NULL); 1067 | 1068 | return self->ops->get_input_buffer_queue(self); 1069 | } 1070 | 1071 | 1072 | int vdec_get_video_dimensions(struct vdec_decoder *self, 1073 | unsigned int *width, 1074 | unsigned int *height, 1075 | unsigned int *sar_width, 1076 | unsigned int *sar_height, 1077 | unsigned int *crop_left, 1078 | unsigned int *crop_top, 1079 | unsigned int *crop_width, 1080 | unsigned int *crop_height) 1081 | { 1082 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self == NULL, EINVAL); 1083 | 1084 | if (!self->configured) { 1085 | VDEC_LOG_ERRNO("decoder is not configured", EAGAIN); 1086 | return -EAGAIN; 1087 | } 1088 | 1089 | if (width != NULL) 1090 | *width = self->video_info.resolution.width; 1091 | if (height != NULL) 1092 | *height = self->video_info.resolution.height; 1093 | if (sar_width != NULL) 1094 | *sar_width = self->video_info.sar.width; 1095 | if (sar_height != NULL) 1096 | *sar_height = self->video_info.sar.height; 1097 | if (crop_left != NULL) 1098 | *crop_left = self->video_info.crop.left; 1099 | if (crop_top != NULL) 1100 | *crop_top = self->video_info.crop.top; 1101 | if (crop_width != NULL) 1102 | *crop_width = self->video_info.crop.width; 1103 | if (crop_height != NULL) 1104 | *crop_height = self->video_info.crop.height; 1105 | 1106 | return 0; 1107 | } 1108 | 1109 | 1110 | enum vdec_decoder_implem vdec_get_used_implem(struct vdec_decoder *self) 1111 | { 1112 | VDEC_LOG_ERRNO_RETURN_VAL_IF( 1113 | self == NULL, EINVAL, VDEC_DECODER_IMPLEM_AUTO); 1114 | 1115 | return self->config.implem; 1116 | } 1117 | -------------------------------------------------------------------------------- /src/vdec_priv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_PRIV_H_ 28 | #define _VDEC_PRIV_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #ifdef _WIN32 40 | # include 41 | #else /* !_WIN32 */ 42 | # include 43 | #endif /* !_WIN32 */ 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #ifdef BUILD_LIBVIDEO_DECODE_FFMPEG 52 | # include 53 | #endif 54 | 55 | #ifdef BUILD_LIBVIDEO_DECODE_MEDIACODEC 56 | # include 57 | #endif 58 | 59 | #ifdef BUILD_LIBVIDEO_DECODE_VIDEOTOOLBOX 60 | # include 61 | #endif 62 | 63 | #ifdef BUILD_LIBVIDEO_DECODE_HISI 64 | # include 65 | #endif 66 | 67 | #ifdef BUILD_LIBVIDEO_DECODE_AML 68 | # include 69 | #endif 70 | 71 | #ifdef BUILD_LIBVIDEO_DECODE_TURBOJPEG 72 | # include 73 | #endif 74 | 75 | #ifdef BUILD_LIBVIDEO_DECODE_QCOM 76 | # include 77 | #endif 78 | 79 | 80 | #if !defined(_WIN32) 81 | # define VDEC_UNUSED __attribute__((unused)) 82 | #else 83 | # define VDEC_UNUSED 84 | #endif 85 | 86 | 87 | static inline void xfree(void **ptr) 88 | { 89 | if (ptr) { 90 | free(*ptr); 91 | *ptr = NULL; 92 | } 93 | } 94 | 95 | 96 | static inline char *xstrdup(const char *s) 97 | { 98 | return s == NULL ? NULL : strdup(s); 99 | } 100 | 101 | 102 | #endif /* !_VDEC_PRIV_H_ */ 103 | -------------------------------------------------------------------------------- /turbojpeg/include/video-decode/vdec_turbojpeg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_TURBOJPEG_H_ 28 | #define _VDEC_TURBOJPEG_H_ 29 | 30 | #include 31 | 32 | #include 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif /* __cplusplus */ 37 | 38 | /* To be used for all public API */ 39 | #ifdef VDEC_API_EXPORTS 40 | # ifdef _WIN32 41 | # define VDEC_API __declspec(dllexport) 42 | # else /* !_WIN32 */ 43 | # define VDEC_API __attribute__((visibility("default"))) 44 | # endif /* !_WIN32 */ 45 | #else /* !VDEC_API_EXPORTS */ 46 | # define VDEC_API 47 | #endif /* !VDEC_API_EXPORTS */ 48 | 49 | 50 | struct vdec_config_turbojpeg { 51 | /* Encoder implementation for this extension. 52 | * Keep this field for compatibility with 'struct venc_config_impl' */ 53 | enum vdec_decoder_implem implem; 54 | 55 | /* Optional output memory pool, 56 | * If set, the decoder will get a mbuf_mem from this pool and fill it 57 | * with the decoded image to avoid memory copies */ 58 | struct mbuf_pool *out_pool; 59 | }; 60 | 61 | 62 | #define VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS 1 63 | 64 | 65 | extern VDEC_API const struct vdec_ops vdec_turbojpeg_ops; 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif /* __cplusplus */ 70 | 71 | 72 | #endif /* !_VDEC_TURBOJPEG_H_ */ 73 | -------------------------------------------------------------------------------- /turbojpeg/src/vdec_turbojpeg.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #define ULOG_TAG vdec_turbojpeg 28 | #include 29 | ULOG_DECLARE_TAG(ULOG_TAG); 30 | 31 | #include "vdec_turbojpeg_priv.h" 32 | 33 | 34 | #define DEFAULT_OUT_BUF_COUNT 15 35 | 36 | static struct vdef_coded_format 37 | supported_formats[VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS]; 38 | static pthread_once_t supported_formats_is_init = PTHREAD_ONCE_INIT; 39 | 40 | static void initialize_supported_formats(void) 41 | { 42 | supported_formats[0] = vdef_jpeg_jfif; 43 | } 44 | 45 | static void call_flush_done(void *userdata) 46 | { 47 | struct vdec_turbojpeg *self = userdata; 48 | 49 | vdec_call_flush_cb(self->base); 50 | } 51 | 52 | static void call_stop_done(void *userdata) 53 | { 54 | struct vdec_turbojpeg *self = userdata; 55 | 56 | vdec_call_stop_cb(self->base); 57 | } 58 | 59 | static void mbox_cb(int fd, uint32_t revents, void *userdata) 60 | { 61 | struct vdec_turbojpeg *self = userdata; 62 | int ret, err; 63 | char message; 64 | 65 | do { 66 | /* Read from the mailbox */ 67 | ret = mbox_peek(self->mbox, &message); 68 | if (ret < 0) { 69 | if (ret != -EAGAIN) 70 | VDEC_LOG_ERRNO("mbox_peek", -ret); 71 | break; 72 | } 73 | 74 | switch (message) { 75 | case VDEC_MSG_FLUSH: 76 | err = pomp_loop_idle_add_with_cookie( 77 | self->base->loop, call_flush_done, self, self); 78 | if (err < 0) { 79 | VDEC_LOG_ERRNO("pomp_loop_idle_add_with_cookie", 80 | -err); 81 | } 82 | break; 83 | case VDEC_MSG_STOP: 84 | err = pomp_loop_idle_add_with_cookie( 85 | self->base->loop, call_stop_done, self, self); 86 | if (err < 0) { 87 | VDEC_LOG_ERRNO("pomp_loop_idle_add_with_cookie", 88 | -err); 89 | } 90 | break; 91 | default: 92 | VDEC_LOGE("unknown message: %c", message); 93 | break; 94 | } 95 | } while (ret == 0); 96 | } 97 | 98 | static void dec_error_evt_cb(struct pomp_evt *evt, void *userdata) 99 | { 100 | struct vdec_turbojpeg *self = userdata; 101 | int status = atomic_exchange(&self->status, 0); 102 | 103 | vdec_call_frame_output_cb(self->base, status, NULL); 104 | } 105 | 106 | 107 | static void dec_out_queue_evt_cb(struct pomp_evt *evt, void *userdata) 108 | { 109 | struct vdec_turbojpeg *self = userdata; 110 | struct mbuf_raw_video_frame *out_frame = NULL; 111 | int ret; 112 | do { 113 | ret = mbuf_raw_video_frame_queue_pop(self->dec_out_queue, 114 | &out_frame); 115 | if (ret == -EAGAIN) { 116 | return; 117 | } else if (ret < 0) { 118 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_queue_pop:dec_out", 119 | -ret); 120 | return; 121 | } 122 | vdec_call_frame_output_cb(self->base, 0, out_frame); 123 | mbuf_raw_video_frame_unref(out_frame); 124 | } while (ret == 0); 125 | } 126 | 127 | static int decode_frame(struct vdec_turbojpeg *self, 128 | struct mbuf_coded_video_frame *in_frame) 129 | { 130 | int ret; 131 | size_t len; 132 | struct vdef_coded_frame in_info; 133 | unsigned char *plane_data[VDEF_RAW_MAX_PLANE_COUNT] = {0}; 134 | size_t plane_size[VDEF_RAW_MAX_PLANE_COUNT] = {0}; 135 | const void *in_data; 136 | struct mbuf_raw_video_frame *out_frame = NULL; 137 | struct vdef_raw_frame out_info = {0}; 138 | struct timespec cur_ts = {0, 0}; 139 | uint64_t ts_us; 140 | struct mbuf_mem *out_mem = NULL; 141 | struct vmeta_frame *metadata = NULL; 142 | size_t offset = 0; 143 | void *mem_data = NULL; 144 | size_t mem_data_size = 0; 145 | size_t conv_mem_size = 0; 146 | unsigned int i; 147 | 148 | if (!in_frame) 149 | return 0; 150 | 151 | ret = mbuf_coded_video_frame_get_frame_info(in_frame, &in_info); 152 | if (ret < 0) { 153 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_get_frame_info", -ret); 154 | return ret; 155 | } 156 | 157 | time_get_monotonic(&cur_ts); 158 | time_timespec_to_us(&cur_ts, &ts_us); 159 | 160 | if (!vdef_coded_format_intersect(&in_info.format, 161 | supported_formats, 162 | VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS)) { 163 | ret = -ENOSYS; 164 | VDEC_LOG_ERRNO( 165 | "unsupported format:" 166 | " " VDEF_CODED_FORMAT_TO_STR_FMT, 167 | -ret, 168 | VDEF_CODED_FORMAT_TO_STR_ARG(&in_info.format)); 169 | return ret; 170 | } 171 | 172 | ret = mbuf_coded_video_frame_get_packed_buffer( 173 | in_frame, &in_data, &len); 174 | if (ret < 0) { 175 | VDEC_LOG_ERRNO("mbuf_coded_video_frame_get_packed_buffer", 176 | -ret); 177 | goto out; 178 | } 179 | 180 | /* Get a memory from the pool */ 181 | ret = mbuf_pool_get(self->out_pool, &out_mem); 182 | if (ret < 0) { 183 | VDEC_LOG_ERRNO("mbuf_pool_get", -ret); 184 | goto out; 185 | } 186 | 187 | ret = mbuf_mem_get_data(out_mem, &mem_data, &mem_data_size); 188 | if (ret < 0) { 189 | VDEC_LOG_ERRNO("mbuf_mem_get_data", -ret); 190 | goto out; 191 | } 192 | 193 | offset = 0; 194 | /* Compute frame size depending on format */ 195 | ret = vdef_calc_raw_frame_size(&self->output_format, 196 | &self->base->video_info.resolution, 197 | NULL, 198 | NULL, 199 | NULL, 200 | NULL, 201 | &(plane_size[0]), 202 | NULL); 203 | if (ret < 0) { 204 | VDEC_LOG_ERRNO("vdef_calc_raw_frame_size", -ret); 205 | goto out; 206 | } 207 | 208 | for (i = 0; i < vdef_get_raw_frame_plane_count(&self->output_format); 209 | i++) { 210 | plane_data[i] = (unsigned char *)mem_data + offset; 211 | offset += plane_size[i]; 212 | } 213 | 214 | if (vdef_raw_format_cmp(&self->base->config.preferred_output_format, 215 | &vdef_nv12)) { 216 | /* As libjpeg-turbo does not support NV12 output format, 217 | * A temporary memory is used to hold U and V planes. 218 | * Y plane will be stored in the output buffer 219 | * (no conversion needed) 220 | * U plane will be stored in the conv_mem, 221 | * V plane will be stored in the conv_mem + U plane offset 222 | * */ 223 | ret = mbuf_mem_get_data( 224 | self->conv_mem, (void *)&plane_data[1], &conv_mem_size); 225 | if (ret < 0) { 226 | VDEC_LOG_ERRNO("mbuf_mem_get_data", -ret); 227 | goto out; 228 | } 229 | plane_data[2] = plane_data[1] + (plane_size[1] / 2); 230 | } 231 | 232 | ret = mbuf_coded_video_frame_add_ancillary_buffer( 233 | in_frame, 234 | VDEC_ANCILLARY_KEY_DEQUEUE_TIME, 235 | &ts_us, 236 | sizeof(ts_us)); 237 | if (ret < 0) 238 | VDEC_LOG_ERRNO("mbuf_coded_video_frame_add_ancillary_buffer", 239 | -ret); 240 | 241 | atomic_fetch_add(&self->base->counters.pushed, 1); 242 | 243 | /* TODO check for tjDecompressToYUVPlanes flags */ 244 | ret = tjDecompressToYUVPlanes(self->tj_handler, 245 | in_data, 246 | len, 247 | (unsigned char **)&plane_data, 248 | self->base->video_info.resolution.width, 249 | NULL, 250 | self->base->video_info.resolution.height, 251 | 0); 252 | if (ret < 0) { 253 | VDEC_LOGE("%s", tjGetErrorStr()); 254 | goto out; 255 | } 256 | 257 | atomic_fetch_add(&self->base->counters.pulled, 1); 258 | 259 | if (vdef_raw_format_cmp(&self->base->config.preferred_output_format, 260 | &vdef_nv12)) { 261 | /* Y plane does not need conversion, 262 | * U and V planes are merged into the output buffer 263 | * (+ Y plane offset) 264 | * using libyuv hardware-accelerated conversion function. 265 | */ 266 | ret = I420ToNV12(NULL, 267 | self->base->video_info.resolution.width, 268 | plane_data[1], 269 | self->base->video_info.resolution.width / 2, 270 | plane_data[2], 271 | self->base->video_info.resolution.width / 2, 272 | NULL, 273 | self->base->video_info.resolution.width, 274 | plane_data[0] + plane_size[0], 275 | self->base->video_info.resolution.width, 276 | self->base->video_info.resolution.width, 277 | self->base->video_info.resolution.height); 278 | if (ret < 0) 279 | VDEC_LOG_ERRNO("I420ToNV12", -ret); 280 | } 281 | 282 | ret = mbuf_coded_video_frame_release_packed_buffer(in_frame, in_data); 283 | if (ret < 0) { 284 | VDEC_LOG_ERRNO("mbuf_coded_video_frame_release_packed_buffer", 285 | -ret); 286 | } 287 | in_data = NULL; 288 | 289 | out_info.info = in_info.info; 290 | out_info.format = self->output_format; 291 | if (vdef_raw_format_cmp(&out_info.format, &vdef_i420)) { 292 | unsigned int stride = self->base->video_info.resolution.width; 293 | out_info.plane_stride[0] = stride; 294 | out_info.plane_stride[1] = stride / 2; 295 | out_info.plane_stride[2] = stride / 2; 296 | } else if (vdef_raw_format_cmp(&out_info.format, &vdef_nv12)) { 297 | unsigned int stride = self->base->video_info.resolution.width; 298 | out_info.plane_stride[0] = stride; 299 | out_info.plane_stride[1] = stride; 300 | out_info.plane_stride[2] = 0; 301 | } else { 302 | ret = -ENOSYS; 303 | VDEC_LOG_ERRNO("unsupported output chroma format", -ret); 304 | goto out; 305 | } 306 | out_info.info.bit_depth = self->base->video_info.bit_depth; 307 | out_info.info.full_range = self->base->video_info.full_range; 308 | out_info.info.color_primaries = self->base->video_info.color_primaries; 309 | out_info.info.transfer_function = 310 | self->base->video_info.transfer_function; 311 | out_info.info.matrix_coefs = self->base->video_info.matrix_coefs; 312 | out_info.info.resolution.width = 313 | self->base->video_info.resolution.width; 314 | out_info.info.resolution.height = 315 | self->base->video_info.resolution.height; 316 | out_info.info.sar = self->base->video_info.sar; 317 | 318 | /* Raw frame creation */ 319 | ret = mbuf_raw_video_frame_new(&out_info, &out_frame); 320 | if (ret < 0) { 321 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_new", -ret); 322 | goto out; 323 | } 324 | 325 | /* Set planes */ 326 | offset = 0; 327 | for (unsigned int i = 0; 328 | i < vdef_get_raw_frame_plane_count(&self->output_format); 329 | i++) { 330 | ret = mbuf_raw_video_frame_set_plane( 331 | out_frame, i, out_mem, offset, plane_size[i]); 332 | if (ret < 0) { 333 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_set_plane", -ret); 334 | goto out; 335 | } 336 | offset += plane_size[i]; 337 | } 338 | 339 | /* Frame ancillary data */ 340 | ret = mbuf_coded_video_frame_foreach_ancillary_data( 341 | in_frame, 342 | mbuf_raw_video_frame_ancillary_data_copier, 343 | out_frame); 344 | if (ret < 0) { 345 | VDEC_LOG_ERRNO("mbuf_coded_video_frame_foreach_ancillary_data", 346 | -ret); 347 | goto out; 348 | } 349 | 350 | /* Frame metadata */ 351 | ret = mbuf_coded_video_frame_get_metadata(in_frame, &metadata); 352 | if (ret == 0) { 353 | ret = mbuf_raw_video_frame_set_metadata(out_frame, metadata); 354 | if (ret < 0) { 355 | VDEC_LOG_ERRNO("mbuf_coded_video_frame_set_metadata", 356 | -ret); 357 | goto out; 358 | } 359 | } else if ((ret < 0) && (ret != -ENOENT)) { 360 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_get_metadata", -ret); 361 | goto out; 362 | } 363 | 364 | time_get_monotonic(&cur_ts); 365 | time_timespec_to_us(&cur_ts, &ts_us); 366 | 367 | ret = mbuf_raw_video_frame_add_ancillary_buffer( 368 | out_frame, 369 | VDEC_ANCILLARY_KEY_OUTPUT_TIME, 370 | &ts_us, 371 | sizeof(ts_us)); 372 | if (ret < 0) 373 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_add_ancillary_buffer", 374 | -ret); 375 | 376 | /* Output the frame */ 377 | ret = mbuf_raw_video_frame_finalize(out_frame); 378 | if (ret < 0) { 379 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_finalize", -ret); 380 | goto out; 381 | } 382 | 383 | ret = mbuf_raw_video_frame_queue_push(self->dec_out_queue, out_frame); 384 | if (ret < 0) { 385 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_queue_push", -ret); 386 | goto out; 387 | } 388 | 389 | out: 390 | if (out_frame) 391 | mbuf_raw_video_frame_unref(out_frame); 392 | 393 | if (out_mem) 394 | mbuf_mem_unref(out_mem); 395 | 396 | if (in_data) { 397 | ret = mbuf_coded_video_frame_release_packed_buffer(in_frame, 398 | in_data); 399 | if (ret < 0) 400 | VDEC_LOG_ERRNO( 401 | "mbuf_coded_video_frame_release_packed_buffer", 402 | -ret); 403 | } 404 | 405 | if (metadata) 406 | vmeta_frame_unref(metadata); 407 | 408 | if (ret < 0) { 409 | /* Notify error */ 410 | atomic_store(&self->status, ret); 411 | pomp_evt_signal(self->dec_error_evt); 412 | } 413 | return ret; 414 | } 415 | 416 | static int complete_flush(struct vdec_turbojpeg *self) 417 | { 418 | int ret; 419 | 420 | if (atomic_load(&self->flush_discard)) { 421 | 422 | /* Flush the input queue */ 423 | ret = mbuf_coded_video_frame_queue_flush(self->in_queue); 424 | if (ret < 0) { 425 | VDEC_LOG_ERRNO( 426 | "mbuf_coded_video_frame_queue_flush:input", 427 | -ret); 428 | return ret; 429 | } 430 | 431 | /* Flush the decoder output queue */ 432 | ret = mbuf_raw_video_frame_queue_flush(self->dec_out_queue); 433 | if (ret < 0) { 434 | VDEC_LOG_ERRNO( 435 | "mbuf_raw_video_frame_queue_flush:dec_out", 436 | -ret); 437 | return ret; 438 | } 439 | } 440 | 441 | atomic_store(&self->flushing, false); 442 | atomic_store(&self->flush_discard, false); 443 | 444 | /* Call the flush callback on the loop */ 445 | char message = VDEC_MSG_FLUSH; 446 | ret = mbox_push(self->mbox, &message); 447 | if (ret < 0) 448 | VDEC_LOG_ERRNO("mbox_push", -ret); 449 | 450 | return ret; 451 | } 452 | 453 | static void check_input_queue(struct vdec_turbojpeg *self) 454 | { 455 | int ret, err = 0; 456 | struct mbuf_coded_video_frame *in_frame; 457 | 458 | ret = mbuf_coded_video_frame_queue_peek(self->in_queue, &in_frame); 459 | while (ret >= 0) { 460 | /* Push the input frame */ 461 | /* Decode the frame */ 462 | ret = decode_frame(self, in_frame); 463 | if (ret < 0) { 464 | if (ret != -EAGAIN) 465 | VDEC_LOG_ERRNO("decode_frame", -ret); 466 | err = -ENOSPC; 467 | } 468 | if (in_frame) { 469 | mbuf_coded_video_frame_unref(in_frame); 470 | /* Pop the frame for real */ 471 | ret = mbuf_coded_video_frame_queue_pop(self->in_queue, 472 | &in_frame); 473 | if (ret < 0) { 474 | VDEC_LOG_ERRNO( 475 | "mbuf_coded_video_frame_queue_pop", 476 | -ret); 477 | break; 478 | } 479 | mbuf_coded_video_frame_unref(in_frame); 480 | } 481 | if (err) 482 | break; 483 | /* Peek the next frame */ 484 | ret = mbuf_coded_video_frame_queue_peek(self->in_queue, 485 | &in_frame); 486 | if (ret < 0 && ret != -EAGAIN && ret != -ENOSPC) 487 | VDEC_LOG_ERRNO("mbuf_coded_video_frame_queue_peek", 488 | -ret); 489 | if (self->flushing && ret == -EAGAIN) { 490 | in_frame = NULL; 491 | if ((atomic_load(&self->flushing)) && 492 | (!atomic_load(&self->flush_discard))) { 493 | ret = complete_flush(self); 494 | if (ret < 0) 495 | VDEC_LOG_ERRNO("complete_flush", -ret); 496 | continue; 497 | 498 | /* Else we proceed to call decode_frame() 499 | * without an input frame to flush the 500 | * decoder */ 501 | } 502 | } 503 | } 504 | 505 | if (self->flushing && ret == -EAGAIN) { 506 | if (((atomic_load(&self->flushing)) && 507 | (!atomic_load(&self->flush_discard)))) { 508 | ret = complete_flush(self); 509 | if (ret < 0) 510 | VDEC_LOG_ERRNO("complete_flush", -ret); 511 | } 512 | } 513 | } 514 | 515 | static void input_event_cb(struct pomp_evt *evt, void *userdata) 516 | { 517 | struct vdec_turbojpeg *self = userdata; 518 | check_input_queue(self); 519 | } 520 | 521 | 522 | static void *decoder_thread(void *ptr) 523 | { 524 | int ret, timeout; 525 | struct vdec_turbojpeg *self = ptr; 526 | struct pomp_loop *loop = NULL; 527 | struct pomp_evt *in_queue_evt = NULL; 528 | char message; 529 | 530 | #if defined(__APPLE__) 531 | # if !TARGET_OS_IPHONE 532 | ret = pthread_setname_np("vdec_turbojpeg"); 533 | if (ret != 0) 534 | VDEC_LOG_ERRNO("pthread_setname_np", ret); 535 | # endif 536 | #else 537 | ret = pthread_setname_np(pthread_self(), "vdec_turbojpeg"); 538 | if (ret != 0) 539 | VDEC_LOG_ERRNO("pthread_setname_np", ret); 540 | #endif 541 | 542 | loop = pomp_loop_new(); 543 | if (!loop) { 544 | VDEC_LOG_ERRNO("pomp_loop_new", ENOMEM); 545 | goto exit; 546 | } 547 | 548 | ret = mbuf_coded_video_frame_queue_get_event(self->in_queue, 549 | &in_queue_evt); 550 | if (ret != 0) { 551 | VDEC_LOG_ERRNO("mbuf_coded_video_frame_queue_get_event", -ret); 552 | goto exit; 553 | } 554 | 555 | ret = pomp_evt_attach_to_loop(in_queue_evt, loop, input_event_cb, self); 556 | if (ret != 0) { 557 | VDEC_LOG_ERRNO("pomp_evt_attach_to_loop", -ret); 558 | goto exit; 559 | } 560 | 561 | while ((!atomic_load(&self->should_stop)) || 562 | (atomic_load(&self->flushing))) { 563 | /* Start flush, discarding all frames */ 564 | if ((atomic_load(&self->flushing)) && 565 | (atomic_load(&self->flush_discard))) { 566 | ret = complete_flush(self); 567 | if (ret < 0) 568 | VDEC_LOG_ERRNO("complete_flush", -ret); 569 | continue; 570 | } 571 | 572 | /* Wait for an input buffer (without dequeueing it) */ 573 | timeout = ((atomic_load(&self->flushing)) && 574 | (!atomic_load(&self->flush_discard))) 575 | ? 0 576 | : 5; 577 | ret = pomp_loop_wait_and_process(loop, timeout); 578 | if (ret < 0 && ret != -ETIMEDOUT) { 579 | VDEC_LOG_ERRNO("pomp_loop_wait_and_process", -ret); 580 | if (!self->should_stop) { 581 | /* Avoid looping on errors */ 582 | usleep(5000); 583 | } 584 | continue; 585 | } else if (ret == -ETIMEDOUT) { 586 | check_input_queue(self); 587 | } 588 | } 589 | 590 | /* Call the stop callback on the loop */ 591 | message = VDEC_MSG_STOP; 592 | ret = mbox_push(self->mbox, &message); 593 | if (ret < 0) 594 | VDEC_LOG_ERRNO("mbox_push", -ret); 595 | 596 | exit: 597 | if (in_queue_evt != NULL && pomp_evt_is_attached(in_queue_evt, loop)) { 598 | ret = pomp_evt_detach_from_loop(in_queue_evt, loop); 599 | if (ret != 0) 600 | VDEC_LOG_ERRNO("pomp_evt_detach_from_loop", -ret); 601 | } 602 | if (loop != NULL) { 603 | ret = pomp_loop_destroy(loop); 604 | if (ret != 0) 605 | VDEC_LOG_ERRNO("pomp_loop_destroy", -ret); 606 | } 607 | 608 | return NULL; 609 | } 610 | 611 | static int get_supported_input_formats(const struct vdef_coded_format **formats) 612 | { 613 | (void)pthread_once(&supported_formats_is_init, 614 | initialize_supported_formats); 615 | *formats = supported_formats; 616 | return VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS; 617 | } 618 | 619 | static int flush(struct vdec_decoder *base, int discard_) 620 | { 621 | struct vdec_turbojpeg *self = NULL; 622 | bool discard = discard_; 623 | 624 | VDEC_LOG_ERRNO_RETURN_ERR_IF(base == NULL, EINVAL); 625 | self = base->derived; 626 | 627 | atomic_store(&self->flushing, true); 628 | atomic_store(&self->flush_discard, discard); 629 | 630 | return 0; 631 | } 632 | 633 | static int stop(struct vdec_decoder *base) 634 | { 635 | struct vdec_turbojpeg *self = NULL; 636 | 637 | VDEC_LOG_ERRNO_RETURN_ERR_IF(base == NULL, EINVAL); 638 | self = base->derived; 639 | 640 | /* Stop the decoding thread */ 641 | atomic_store(&self->should_stop, true); 642 | return 0; 643 | } 644 | 645 | static int destroy(struct vdec_decoder *base) 646 | { 647 | int err; 648 | struct vdec_turbojpeg *self = NULL; 649 | 650 | VDEC_LOG_ERRNO_RETURN_ERR_IF(base == NULL, EINVAL); 651 | 652 | self = base->derived; 653 | if (self == NULL) 654 | return 0; 655 | 656 | /* Stop and join the decoding thread */ 657 | err = stop(base); 658 | if (err < 0) 659 | VDEC_LOG_ERRNO("stop", -err); 660 | if (self->thread_launched) { 661 | err = pthread_join(self->thread, NULL); 662 | if (err != 0) 663 | VDEC_LOG_ERRNO("pthread_join", err); 664 | } 665 | 666 | /* Free the resources */ 667 | if (self->dec_error_evt != NULL) { 668 | if (pomp_evt_is_attached(self->dec_error_evt, base->loop)) { 669 | err = pomp_evt_detach_from_loop(self->dec_error_evt, 670 | base->loop); 671 | if (err < 0) 672 | VDEC_LOG_ERRNO("pomp_evt_detach_from_loop", 673 | -err); 674 | } 675 | 676 | pomp_evt_destroy(self->dec_error_evt); 677 | self->dec_error_evt = NULL; 678 | } 679 | if (self->in_queue != NULL) { 680 | err = mbuf_coded_video_frame_queue_destroy(self->in_queue); 681 | if (err < 0) 682 | VDEC_LOG_ERRNO( 683 | "mbuf_coded_video_frame_queue_destroy:input", 684 | -err); 685 | } 686 | if (self->dec_out_queue_evt != NULL && 687 | pomp_evt_is_attached(self->dec_out_queue_evt, base->loop)) { 688 | err = pomp_evt_detach_from_loop(self->dec_out_queue_evt, 689 | base->loop); 690 | if (err < 0) 691 | VDEC_LOG_ERRNO("pomp_evt_detach_from_loop", -err); 692 | } 693 | if (self->dec_out_queue != NULL) { 694 | err = mbuf_raw_video_frame_queue_destroy(self->dec_out_queue); 695 | if (err < 0) 696 | VDEC_LOG_ERRNO( 697 | "mbuf_raw_video_frame_queue_destroy:dec_out", 698 | -err); 699 | } 700 | if (self->out_pool != NULL && !self->external_out_pool) { 701 | err = mbuf_pool_destroy(self->out_pool); 702 | if (err < 0) 703 | VDEC_LOG_ERRNO("mbuf_pool_destroy:dec_out", -err); 704 | } 705 | if (self->conv_mem != NULL) { 706 | err = mbuf_mem_unref(self->conv_mem); 707 | if (err < 0) 708 | VDEC_LOG_ERRNO("mbuf_mem_unref", -err); 709 | } 710 | if (self->mbox) { 711 | err = pomp_loop_remove(base->loop, 712 | mbox_get_read_fd(self->mbox)); 713 | if (err < 0) 714 | VDEC_LOG_ERRNO("pomp_loop_remove", -err); 715 | mbox_destroy(self->mbox); 716 | } 717 | if (self->tj_handler) { 718 | err = tjDestroy(self->tj_handler); 719 | if (err < 0) 720 | VDEC_LOGE("%s", tjGetErrorStr()); 721 | } 722 | 723 | err = pomp_loop_idle_remove_by_cookie(base->loop, self); 724 | if (err < 0) 725 | VDEC_LOG_ERRNO("pomp_loop_idle_remove_by_cookie", -err); 726 | 727 | xfree((void **)&self); 728 | base->derived = NULL; 729 | return 0; 730 | } 731 | 732 | static bool input_filter(struct mbuf_coded_video_frame *frame, void *userdata) 733 | { 734 | int ret; 735 | const void *tmp; 736 | size_t tmplen; 737 | struct vdec_turbojpeg *self = userdata; 738 | struct vdef_coded_frame info; 739 | 740 | VDEC_LOG_ERRNO_RETURN_ERR_IF(self == NULL, false); 741 | 742 | if (atomic_load(&self->flushing)) 743 | return false; 744 | 745 | ret = mbuf_coded_video_frame_get_frame_info(frame, &info); 746 | if (ret < 0) 747 | return false; 748 | 749 | /* Pass default filters first */ 750 | if (!vdec_default_input_filter_internal( 751 | self->base, 752 | frame, 753 | &info, 754 | supported_formats, 755 | VDEC_TURBOJPEG_NB_SUPPORTED_FORMATS)) 756 | return false; 757 | 758 | /* Input frame must be packed */ 759 | ret = mbuf_coded_video_frame_get_packed_buffer(frame, &tmp, &tmplen); 760 | if (ret != 0) 761 | return false; 762 | 763 | mbuf_coded_video_frame_release_packed_buffer(frame, tmp); 764 | 765 | vdec_default_input_filter_internal_confirm_frame( 766 | self->base, frame, &info); 767 | 768 | return true; 769 | } 770 | 771 | static int create(struct vdec_decoder *base) 772 | { 773 | int ret = 0; 774 | struct vdec_turbojpeg *self = NULL; 775 | struct vdec_config_turbojpeg *specific; 776 | struct mbuf_coded_video_frame_queue_args queue_args = { 777 | .filter = input_filter, 778 | }; 779 | 780 | VDEC_LOG_ERRNO_RETURN_ERR_IF(base == NULL, EINVAL); 781 | 782 | (void)pthread_once(&supported_formats_is_init, 783 | initialize_supported_formats); 784 | 785 | /* Check the configuration */ 786 | if (base->config.encoding != VDEF_ENCODING_MJPEG) { 787 | ret = -EINVAL; 788 | VDEC_LOG_ERRNO("invalid encoding: %s", 789 | -ret, 790 | vdef_encoding_to_str(base->config.encoding)); 791 | return ret; 792 | } 793 | 794 | if (vdef_is_raw_format_valid(&base->config.preferred_output_format) && 795 | !vdef_raw_format_cmp(&base->config.preferred_output_format, 796 | &vdef_i420) && 797 | !vdef_raw_format_cmp(&base->config.preferred_output_format, 798 | &vdef_nv12)) { 799 | ret = -EINVAL; 800 | VDEC_LOG_ERRNO("invalid preferred_output_format", -ret); 801 | goto error; 802 | } 803 | 804 | self = calloc(1, sizeof(*self)); 805 | if (self == NULL) 806 | return -ENOMEM; 807 | 808 | self->base = base; 809 | base->derived = self; 810 | if (vdef_is_raw_format_valid(&base->config.preferred_output_format)) 811 | self->output_format = base->config.preferred_output_format; 812 | else 813 | self->output_format = vdef_i420; 814 | self->thread_launched = false; 815 | 816 | queue_args.filter_userdata = self; 817 | 818 | VDEC_LOGI("TurboJPEG implementation"); 819 | 820 | self->tj_handler = tjInitDecompress(); 821 | if (!self->tj_handler) { 822 | VDEC_LOGE("%s", tjGetErrorStr()); 823 | goto error; 824 | } 825 | 826 | specific = (struct vdec_config_turbojpeg *)vdec_config_get_specific( 827 | &base->config, VDEC_DECODER_IMPLEM_TURBOJPEG); 828 | 829 | if (specific && specific->out_pool) { 830 | self->out_pool = specific->out_pool; 831 | self->external_out_pool = true; 832 | } 833 | 834 | /* Initialize the mailbox for inter-thread messages */ 835 | self->mbox = mbox_new(1); 836 | if (self->mbox == NULL) { 837 | ret = -ENOMEM; 838 | VDEC_LOG_ERRNO("mbox_new", -ret); 839 | goto error; 840 | } 841 | ret = pomp_loop_add(base->loop, 842 | mbox_get_read_fd(self->mbox), 843 | POMP_FD_EVENT_IN, 844 | &mbox_cb, 845 | self); 846 | if (ret < 0) { 847 | VDEC_LOG_ERRNO("pomp_loop_add", -ret); 848 | goto error; 849 | } 850 | 851 | /* Create the input buffers queue */ 852 | ret = mbuf_coded_video_frame_queue_new_with_args(&queue_args, 853 | &self->in_queue); 854 | if (ret < 0) { 855 | VDEC_LOG_ERRNO( 856 | "mbuf_coded_video_frame_queue_new_with_args:input", 857 | -ret); 858 | goto error; 859 | } 860 | 861 | /* Create the decoder output buffers queue */ 862 | ret = mbuf_raw_video_frame_queue_new(&self->dec_out_queue); 863 | if (ret < 0) { 864 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_queue_new:dec_out", -ret); 865 | goto error; 866 | } 867 | 868 | ret = mbuf_raw_video_frame_queue_get_event(self->dec_out_queue, 869 | &self->dec_out_queue_evt); 870 | if (ret < 0) { 871 | VDEC_LOG_ERRNO("mbuf_raw_video_frame_queue_get_event", -ret); 872 | goto error; 873 | } 874 | 875 | ret = pomp_evt_attach_to_loop(self->dec_out_queue_evt, 876 | base->loop, 877 | &dec_out_queue_evt_cb, 878 | self); 879 | if (ret < 0) { 880 | VDEC_LOG_ERRNO("pomp_evt_attach_to_loop", -ret); 881 | goto error; 882 | } 883 | 884 | self->dec_error_evt = pomp_evt_new(); 885 | if (self->dec_error_evt == NULL) { 886 | ret = -ENOMEM; 887 | VDEC_LOG_ERRNO("pomp_evt_new", -ret); 888 | goto error; 889 | } 890 | 891 | ret = pomp_evt_attach_to_loop( 892 | self->dec_error_evt, base->loop, &dec_error_evt_cb, self); 893 | if (ret < 0) { 894 | VDEC_LOG_ERRNO("pomp_evt_attach_to_loop", -ret); 895 | goto error; 896 | } 897 | 898 | /* Create the decoder thread */ 899 | ret = pthread_create(&self->thread, NULL, decoder_thread, (void *)self); 900 | if (ret != 0) { 901 | ret = -ret; 902 | VDEC_LOG_ERRNO("pthread_create", -ret); 903 | goto error; 904 | } 905 | 906 | self->thread_launched = true; 907 | 908 | return 0; 909 | 910 | error: 911 | /* Cleanup on error */ 912 | destroy(base); 913 | return ret; 914 | } 915 | 916 | static struct mbuf_pool *get_input_buffer_pool(struct vdec_decoder *base) 917 | { 918 | /* No input buffer pool allocated: use the application's */ 919 | return NULL; 920 | } 921 | 922 | static struct mbuf_coded_video_frame_queue * 923 | get_input_buffer_queue(struct vdec_decoder *base) 924 | { 925 | struct vdec_turbojpeg *self = NULL; 926 | 927 | self = (struct vdec_turbojpeg *)base->derived; 928 | 929 | return self->in_queue; 930 | } 931 | 932 | static int set_jpeg_params(struct vdec_decoder *base) 933 | { 934 | int ret; 935 | struct vdec_turbojpeg *self = NULL; 936 | size_t pool_count = DEFAULT_OUT_BUF_COUNT; 937 | ssize_t pool_size; 938 | size_t plane_size[VDEF_RAW_MAX_PLANE_COUNT] = {0}; 939 | 940 | self = (struct vdec_turbojpeg *)base->derived; 941 | 942 | /* Use preferred_min_out_buf_count if greater than default pool count */ 943 | if (base->config.preferred_min_out_buf_count != 0 && 944 | base->config.preferred_min_out_buf_count > pool_count) 945 | pool_count = base->config.preferred_min_out_buf_count; 946 | 947 | /* Compute frame size depending on format */ 948 | ret = vdef_calc_raw_frame_size(&self->output_format, 949 | &base->video_info.resolution, 950 | NULL, 951 | NULL, 952 | NULL, 953 | NULL, 954 | &(plane_size[0]), 955 | NULL); 956 | if (ret < 0) { 957 | VDEC_LOG_ERRNO("vdef_calc_raw_frame_size", -ret); 958 | return ret; 959 | } 960 | 961 | pool_size = 0; 962 | for (unsigned int i = 0; 963 | i < vdef_get_raw_frame_plane_count(&self->output_format); 964 | i++) { 965 | pool_size += plane_size[i]; 966 | } 967 | 968 | /* Create pool for raw output frames, if needed */ 969 | if (self->out_pool == NULL) { 970 | ret = mbuf_pool_new(mbuf_mem_generic_impl, 971 | pool_size, 972 | pool_count, 973 | MBUF_POOL_NO_GROW, 974 | 0, 975 | "vdec_turbojpeg", 976 | &self->out_pool); 977 | if (ret < 0) { 978 | VDEC_LOG_ERRNO("mbuf_pool_new", -ret); 979 | return ret; 980 | } 981 | } 982 | 983 | /* Create an extra memory to merge UV planes, if needed */ 984 | if (vdef_raw_format_cmp(&self->base->config.preferred_output_format, 985 | &vdef_nv12)) { 986 | /* Memory size is total size minus Y plane size */ 987 | size_t capacity = pool_size - plane_size[0]; 988 | 989 | ret = mbuf_mem_generic_new(capacity, &self->conv_mem); 990 | if (ret < 0) { 991 | VDEC_LOG_ERRNO("mbuf_mem_generic_new", -ret); 992 | return ret; 993 | } 994 | } 995 | 996 | return 0; 997 | } 998 | 999 | const struct vdec_ops vdec_turbojpeg_ops = { 1000 | .get_supported_input_formats = get_supported_input_formats, 1001 | .create = create, 1002 | .flush = flush, 1003 | .stop = stop, 1004 | .destroy = destroy, 1005 | .get_input_buffer_pool = get_input_buffer_pool, 1006 | .get_input_buffer_queue = get_input_buffer_queue, 1007 | .set_jpeg_params = set_jpeg_params, 1008 | }; 1009 | -------------------------------------------------------------------------------- /turbojpeg/src/vdec_turbojpeg_priv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_TURBOJPEG_PRIV_H_ 28 | #define _VDEC_TURBOJPEG_PRIV_H_ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #if defined(__APPLE__) 35 | # include 36 | #endif 37 | 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | 52 | #include 53 | 54 | #define VDEC_MSG_FLUSH 'f' 55 | #define VDEC_MSG_STOP 's' 56 | #define SOFTMPEG_MAX_PLANES 3 57 | 58 | static inline void xfree(void **ptr) 59 | { 60 | if (ptr) { 61 | free(*ptr); 62 | *ptr = NULL; 63 | } 64 | } 65 | 66 | struct vdec_turbojpeg { 67 | struct vdec_decoder *base; 68 | 69 | struct mbuf_coded_video_frame_queue *in_queue; 70 | struct mbuf_raw_video_frame_queue *dec_out_queue; 71 | struct pomp_evt *dec_out_queue_evt; 72 | struct mbuf_pool *out_pool; 73 | /* Specific: indicate that out_pool is external */ 74 | bool external_out_pool; 75 | /* I420 to NV12 conversion memory for UV planes */ 76 | struct mbuf_mem *conv_mem; 77 | 78 | tjhandle tj_handler; 79 | 80 | struct vdef_raw_format output_format; 81 | 82 | pthread_t thread; 83 | bool thread_launched; 84 | atomic_bool should_stop; 85 | atomic_bool flushing; 86 | atomic_bool flush_discard; 87 | struct mbox *mbox; 88 | 89 | struct pomp_evt *dec_error_evt; 90 | atomic_int status; 91 | }; 92 | 93 | 94 | #endif /* !_VDEC_TURBOJPEG_PRIV_H_ */ 95 | -------------------------------------------------------------------------------- /videotoolbox/include/video-decode/vdec_videotoolbox.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_VIDEOTOOLBOX_H_ 28 | #define _VDEC_VIDEOTOOLBOX_H_ 29 | 30 | #include 31 | #include 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif /* __cplusplus */ 36 | 37 | /* To be used for all public API */ 38 | #ifdef VDEC_API_EXPORTS 39 | # ifdef _WIN32 40 | # define VDEC_API __declspec(dllexport) 41 | # else /* !_WIN32 */ 42 | # define VDEC_API __attribute__((visibility("default"))) 43 | # endif /* !_WIN32 */ 44 | #else /* !VDEC_API_EXPORTS */ 45 | # define VDEC_API 46 | #endif /* !VDEC_API_EXPORTS */ 47 | 48 | 49 | #define VDEC_VIDEOTOOLBOX_NB_SUPPORTED_FORMATS 2 50 | 51 | 52 | extern VDEC_API const struct vdec_ops vdec_videotoolbox_ops; 53 | 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif /* __cplusplus */ 58 | 59 | 60 | #endif /* !_VDEC_VIDEOTOOLBOX_H_ */ 61 | -------------------------------------------------------------------------------- /videotoolbox/src/vdec_videotoolbox_priv.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 Parrot Drones SAS 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the Parrot Drones SAS Company nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PARROT DRONES SAS COMPANY BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _VDEC_VIDEOTOOLBOX_PRIV_H_ 28 | #define _VDEC_VIDEOTOOLBOX_PRIV_H_ 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | 48 | 49 | #define VDEC_VIDEOTOOLBOX_OUT_POOL_DEFAULT_MIN_BUF_COUNT 10 50 | 51 | 52 | enum vdec_videotoolbox_message_type { 53 | VDEC_VIDEOTOOLBOX_MESSAGE_TYPE_FLUSH = 'f', 54 | VDEC_VIDEOTOOLBOX_MESSAGE_TYPE_STOP = 's', 55 | VDEC_VIDEOTOOLBOX_MESSAGE_TYPE_ERROR = 'e', 56 | }; 57 | 58 | 59 | struct vdec_videotoolbox_message { 60 | enum vdec_videotoolbox_message_type type; 61 | int error; 62 | }; 63 | 64 | 65 | struct vdec_videotoolbox { 66 | struct vdec_decoder *base; 67 | struct mbuf_coded_video_frame_queue *in_queue; 68 | struct mbuf_raw_video_frame_queue *out_queue; 69 | struct pomp_evt *out_queue_evt; 70 | CMVideoFormatDescriptionRef format_desc_ref; 71 | VTDecompressionSessionRef decompress_ref; 72 | 73 | pthread_t thread; 74 | bool thread_launched; 75 | atomic_bool should_stop; 76 | atomic_bool flush_required; 77 | atomic_bool flush; 78 | atomic_bool flushing; 79 | atomic_bool flush_discard; 80 | struct mbox *mbox; 81 | atomic_bool need_sync; 82 | }; 83 | 84 | #endif /* !_VDEC_VIDEOTOOLBOX_PRIV_H_ */ 85 | --------------------------------------------------------------------------------