History

avcodec/ohdec: Add h264/hevc OpenHarmony decoders

Zhao Zhili committed 1 year ago

Commit e7f44f81 parent fbda5ff7 files · +908 −1Browse files

Unified · Split

7 files
  1. configure +4 −0
  2. libavcodec/Makefile +3 −0
  3. libavcodec/allcodecs.c +2 −0
  4. libavcodec/ohcodec.c +71 −0
  5. libavcodec/ohcodec.h +56 −0
  6. libavcodec/ohdec.c +771 −0
  7. libavcodec/version.h +1 −1
configure+4−0
@@ -3411,6 +3411,8 @@ h264_mf_encoder_deps="mediafoundation" · 3410 unmodified lines
3411h264_mmal_decoder_deps="mmal"3411h264_mmal_decoder_deps="mmal"
3412h264_nvenc_encoder_deps="nvenc"3412h264_nvenc_encoder_deps="nvenc"
3413h264_nvenc_encoder_select="atsc_a53"3413h264_nvenc_encoder_select="atsc_a53"
3414h264_oh_decoder_deps="ohcodec"
3415h264_oh_decoder_select="h264_mp4toannexb_bsf"
3414h264_omx_encoder_deps="omx"3416h264_omx_encoder_deps="omx"
3415h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec"3417h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec"
3416h264_qsv_encoder_select="atsc_a53 qsvenc"3418h264_qsv_encoder_select="atsc_a53 qsvenc"
@@ -3433,6 +3435,8 @@ hevc_mediacodec_encoder_select="extract_extradata_bsf hevc_metadata" · 16 unmodified lines
3433hevc_mf_encoder_deps="mediafoundation"3435hevc_mf_encoder_deps="mediafoundation"
3434hevc_nvenc_encoder_deps="nvenc"3436hevc_nvenc_encoder_deps="nvenc"
3435hevc_nvenc_encoder_select="atsc_a53"3437hevc_nvenc_encoder_select="atsc_a53"
3438hevc_oh_decoder_deps="ohcodec"
3439hevc_oh_decoder_select="hevc_mp4toannexb_bsf"
3436hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec"3440hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec"
3437hevc_qsv_encoder_select="hevcparse qsvenc"3441hevc_qsv_encoder_select="hevcparse qsvenc"
3438hevc_rkmpp_decoder_deps="rkmpp"3442hevc_rkmpp_decoder_deps="rkmpp"
libavcodec/Makefile+3−0
@@ -428,6 +428,7 @@ OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o · 427 unmodified lines
428OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o428OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o
429OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o429OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
430OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o430OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o
431OBJS-$(CONFIG_H264_OH_DECODER) += ohcodec.o ohdec.o
431OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o432OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o
432OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o433OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o
433OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o434OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o
@@ -456,6 +457,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o · 22 unmodified lines
456OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o457OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o
457OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o458OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o
458OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o459OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o
460OBJS-$(CONFIG_HEVC_OH_DECODER) += ohcodec.o ohdec.o
459OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o461OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o
460OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o462OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o
461OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o463OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o
@@ -1314,6 +1316,7 @@ SKIPHEADERS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.h mediacodec_surf · 852 unmodified lines
1314SKIPHEADERS-$(CONFIG_MEDIAFOUNDATION) += mf_utils.h1316SKIPHEADERS-$(CONFIG_MEDIAFOUNDATION) += mf_utils.h
1315SKIPHEADERS-$(CONFIG_NVDEC) += nvdec.h1317SKIPHEADERS-$(CONFIG_NVDEC) += nvdec.h
1316SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h1318SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h
1319SKIPHEADERS-$(CONFIG_OHCODEC) += ohcodec.h
1317SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h1320SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h
1318SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h1321SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h
1319SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_hevc.h vaapi_encode.h1322SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_hevc.h vaapi_encode.h
libavcodec/allcodecs.c+2−0
@@ -860,6 +860,7 @@ extern const FFCodec ff_h264_amf_decoder; · 859 unmodified lines
860extern const FFCodec ff_h264_cuvid_decoder;860extern const FFCodec ff_h264_cuvid_decoder;
861extern const FFCodec ff_h264_mf_encoder;861extern const FFCodec ff_h264_mf_encoder;
862extern const FFCodec ff_h264_nvenc_encoder;862extern const FFCodec ff_h264_nvenc_encoder;
863extern const FFCodec ff_h264_oh_decoder;
863extern const FFCodec ff_h264_omx_encoder;864extern const FFCodec ff_h264_omx_encoder;
864extern const FFCodec ff_h264_qsv_encoder;865extern const FFCodec ff_h264_qsv_encoder;
865extern const FFCodec ff_h264_v4l2m2m_encoder;866extern const FFCodec ff_h264_v4l2m2m_encoder;
@@ -874,6 +875,7 @@ extern const FFCodec ff_hevc_mediacodec_decoder; · 8 unmodified lines
874extern const FFCodec ff_hevc_mediacodec_encoder;875extern const FFCodec ff_hevc_mediacodec_encoder;
875extern const FFCodec ff_hevc_mf_encoder;876extern const FFCodec ff_hevc_mf_encoder;
876extern const FFCodec ff_hevc_nvenc_encoder;877extern const FFCodec ff_hevc_nvenc_encoder;
878extern const FFCodec ff_hevc_oh_decoder;
877extern const FFCodec ff_hevc_qsv_encoder;879extern const FFCodec ff_hevc_qsv_encoder;
878extern const FFCodec ff_hevc_v4l2m2m_encoder;880extern const FFCodec ff_hevc_v4l2m2m_encoder;
879extern const FFCodec ff_hevc_vaapi_encoder;881extern const FFCodec ff_hevc_vaapi_encoder;
libavcodec/ohcodec.c+71−0
@@ -0,0 +1,71 @@
1/*
2 * This file is part of FFmpeg.
3 *
4 * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.com>
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "ohcodec.h"
22
23#include "libavutil/error.h"
24
25int ff_oh_err_to_ff_err(OH_AVErrCode err)
26{
27 switch (err) {
28 case AV_ERR_OK:
29 return 0;
30 case AV_ERR_NO_MEMORY:
31 return AVERROR(ENOMEM);
32 case AV_ERR_OPERATE_NOT_PERMIT:
33 return AVERROR(EPERM);
34 case AV_ERR_INVALID_VAL:
35 return AVERROR(EINVAL);
36 case AV_ERR_IO:
37 return AVERROR(EIO);
38 case AV_ERR_TIMEOUT:
39 return AVERROR(ETIMEDOUT);
40 case AV_ERR_UNKNOWN:
41 return AVERROR_UNKNOWN;
42 case AV_ERR_SERVICE_DIED:
43 return AVERROR_EXTERNAL;
44 case AV_ERR_INVALID_STATE:
45 return AVERROR(EINVAL);
46 case AV_ERR_UNSUPPORT:
47 return AVERROR(ENOTSUP);
48 default:
49 return AVERROR_EXTERNAL;
50 }
51}
52
53static const struct {
54 OH_AVPixelFormat oh_pix;
55 enum AVPixelFormat pix;
56} oh_pix_map[] = {
57 {AV_PIXEL_FORMAT_NV12, AV_PIX_FMT_NV12},
58 {AV_PIXEL_FORMAT_NV21, AV_PIX_FMT_NV21},
59 {AV_PIXEL_FORMAT_YUVI420, AV_PIX_FMT_YUV420P},
60 {AV_PIXEL_FORMAT_SURFACE_FORMAT, AV_PIX_FMT_OHCODEC},
61};
62
63enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix)
64{
65 for (size_t i = 0; i < FF_ARRAY_ELEMS(oh_pix_map); i++)
66 if (oh_pix_map[i].oh_pix == oh_pix)
67 return oh_pix_map[i].pix;
68
69 return AV_PIX_FMT_NONE;
70}
71
libavcodec/ohcodec.h+56−0
@@ -0,0 +1,56 @@
1/*
2 * This file is part of FFmpeg.
3 *
4 * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.com>
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#ifndef AVCODEC_OHCODEC_H
22#define AVCODEC_OHCODEC_H
23
24#include <multimedia/player_framework/native_avbuffer.h>
25#include <multimedia/player_framework/native_avcodec_base.h>
26#include <multimedia/player_framework/native_averrors.h>
27#include <multimedia/player_framework/native_avformat.h>
28
29#include "libavutil/pixfmt.h"
30
31#include "codec_id.h"
32
33typedef struct OHBufferQueueItem {
34 uint32_t index;
35 OH_AVBuffer *buffer;
36} OHBufferQueueItem;
37
38int ff_oh_err_to_ff_err(OH_AVErrCode err);
39
40static inline const char *ff_oh_mime(enum AVCodecID codec_id, void *log)
41{
42 switch (codec_id) {
43 case AV_CODEC_ID_H264:
44 return OH_AVCODEC_MIMETYPE_VIDEO_AVC;
45 case AV_CODEC_ID_HEVC:
46 return OH_AVCODEC_MIMETYPE_VIDEO_HEVC;
47 default:
48 av_log(log, AV_LOG_ERROR, "Unsupported codec %s\n",
49 avcodec_get_name(codec_id));
50 return NULL;
51 }
52}
53
54enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix);
55
56#endif
libavcodec/ohdec.c+771−0
@@ -0,0 +1,771 @@
1/*
2 * This file is part of FFmpeg.
3 *
4 * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.com>
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "config_components.h"
22
23#include <stdbool.h>
24#include <multimedia/player_framework/native_avcapability.h>
25#include <multimedia/player_framework/native_avcodec_videodecoder.h>
26
27#include "libavutil/fifo.h"
28#include "libavutil/hwcontext_oh.h"
29#include "libavutil/imgutils.h"
30#include "libavutil/mem.h"
31#include "libavutil/opt.h"
32#include "libavutil/thread.h"
33
34#include "avcodec.h"
35#include "codec_internal.h"
36#include "decode.h"
37#include "hwconfig.h"
38#include "ohcodec.h"
39
40typedef struct OHCodecDecContext {
41 AVClass *avclass;
42 OH_AVCodec *dec;
43 /* A reference count to dec. Each hardware frame has a reference count to
44 * dec. dec will be destroyed only after oh_decode_close and all hardware
45 * frames have been released.
46 */
47 AVBufferRef *dec_ref;
48
49 AVMutex input_mutex;
50 AVCond input_cond;
51 AVFifo *input_queue;
52
53 AVMutex output_mutex;
54 AVCond output_cond;
55 AVFifo *output_queue;
56
57 AVPacket pkt;
58
59 int decode_status;
60 bool eof_sent;
61
62 bool output_to_window;
63 bool got_stream_info;
64 int width;
65 int height;
66 int stride;
67 int slice_height;
68 OH_AVPixelFormat pix_fmt;
69
70 char *name;
71 int allow_sw;
72} OHCodecDecContext;
73
74typedef struct OHCodecBuffer {
75 uint32_t index;
76 OH_AVBuffer *buffer;
77 AVBufferRef *dec_ref;
78} OHCodecBuffer;
79
80static void oh_decode_release(void *opaque, uint8_t *data)
81{
82 OH_AVCodec *dec = (OH_AVCodec *)data;
83 OH_AVErrCode err = OH_VideoDecoder_Destroy(dec);
84 if (err == AV_ERR_OK)
85 av_log(NULL, AV_LOG_DEBUG, "Destroy decoder success\n");
86 else
87 av_log(NULL, AV_LOG_ERROR, "Destroy decoder failed, %d, %s\n",
88 err, av_err2str(ff_oh_err_to_ff_err(err)));
89}
90
91static int oh_decode_create(OHCodecDecContext *s, AVCodecContext *avctx)
92{
93 const char *name = s->name;
94
95 if (!name) {
96 const char *mime = ff_oh_mime(avctx->codec_id, avctx);
97 if (!mime)
98 return AVERROR_BUG;
99 OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(mime, false, HARDWARE);
100 if (!cap) {
101 if (!s->allow_sw) {
102 av_log(avctx, AV_LOG_ERROR, "Failed to get hardware codec %s\n", mime);
103 return AVERROR_EXTERNAL;
104 }
105 av_log(avctx, AV_LOG_WARNING,
106 "Failed to get hardware codec %s, try software backend\n", mime);
107 cap = OH_AVCodec_GetCapabilityByCategory(mime, false, SOFTWARE);
108 if (!cap) {
109 av_log(avctx, AV_LOG_ERROR, "Failed to get software codec %s\n", mime);
110 return AVERROR_EXTERNAL;
111 }
112 }
113 name = OH_AVCapability_GetName(cap);
114 if (!name)
115 return AVERROR_EXTERNAL;
116 }
117
118 s->dec = OH_VideoDecoder_CreateByName(name);
119 if (!s->dec) {
120 av_log(avctx, AV_LOG_ERROR, "Create decoder with name %s failed\n", name);
121 return AVERROR_EXTERNAL;
122 }
123 av_log(avctx, AV_LOG_DEBUG, "Create decoder %s success\n", name);
124
125 s->dec_ref = av_buffer_create((uint8_t *)s->dec, 0, oh_decode_release,
126 NULL, 0);
127 if (!s->dec_ref)
128 return AVERROR(ENOMEM);
129
130 return 0;
131}
132
133static int oh_decode_set_format(OHCodecDecContext *s, AVCodecContext *avctx)
134{
135 int ret;
136 OHNativeWindow *window = NULL;
137
138 if (avctx->hw_device_ctx) {
139 AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data);
140 if (device_ctx->type == AV_HWDEVICE_TYPE_OHCODEC) {
141 AVOHCodecDeviceContext *dev = device_ctx->hwctx;
142 window = dev->native_window;
143 s->output_to_window = true;
144 } else {
145 av_log(avctx, AV_LOG_WARNING, "Ignore invalid hw device type %s\n",
146 av_hwdevice_get_type_name(device_ctx->type));
147 }
148 }
149
150 if (avctx->width <= 0 || avctx->height <= 0) {
151 av_log(avctx, AV_LOG_ERROR,
152 "Invalid width/height (%dx%d), width and height are mandatory for ohcodec\n",
153 avctx->width, avctx->height);
154 return AVERROR(EINVAL);
155 }
156
157 OH_AVFormat *format = OH_AVFormat_Create();
158 if (!format)
159 return AVERROR(ENOMEM);
160
161 OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, avctx->width);
162 OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, avctx->height);
163 if (!s->output_to_window)
164 OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT,
165 AV_PIXEL_FORMAT_NV12);
166 else
167 OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT,
168 AV_PIXEL_FORMAT_SURFACE_FORMAT);
169 OH_AVErrCode err = OH_VideoDecoder_Configure(s->dec, format);
170 OH_AVFormat_Destroy(format);
171 if (err != AV_ERR_OK) {
172 ret = ff_oh_err_to_ff_err(err);
173 av_log(avctx, AV_LOG_ERROR, "Decoder configure failed, %d, %s\n",
174 err, av_err2str(ret));
175 return ret;
176 }
177
178 if (s->output_to_window) {
179 err = OH_VideoDecoder_SetSurface(s->dec, window);
180 if (err != AV_ERR_OK) {
181 ret = ff_oh_err_to_ff_err(err);
182 av_log(avctx, AV_LOG_ERROR, "Set surface failed, %d, %s\n",
183 err, av_err2str(ret));
184 return ret;
185 }
186 }
187
188 return 0;
189}
190
191static void oh_decode_on_err(OH_AVCodec *codec, int32_t err, void *userdata)
192{
193 AVCodecContext *avctx = userdata;
194 OHCodecDecContext *s = avctx->priv_data;
195
196 // Careful on the lock order.
197 // Always lock input first.
198 ff_mutex_lock(&s->input_mutex);
199 ff_mutex_lock(&s->output_mutex);
200 s->decode_status = ff_oh_err_to_ff_err(err);
201 ff_mutex_unlock(&s->output_mutex);
202 ff_mutex_unlock(&s->input_mutex);
203
204 ff_cond_signal(&s->output_cond);
205 ff_cond_signal(&s->input_cond);
206}
207
208static void oh_decode_on_stream_changed(OH_AVCodec *codec, OH_AVFormat *format,
209 void *userdata)
210{
211 AVCodecContext *avctx = userdata;
212 OHCodecDecContext *s = avctx->priv_data;
213 int32_t n;
214 double d;
215
216 if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_WIDTH, &s->width) ||
217 !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_PIC_HEIGHT, &s->height) ||
218 !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &s->stride) ||
219 !OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT,
220 &s->slice_height)) {
221 av_log(avctx, AV_LOG_ERROR, "Get dimension info from format failed\n");
222 goto out;
223 }
224
225 if (ff_set_dimensions(avctx, s->width, s->height) < 0)
226 goto out;
227
228 if (s->stride <= 0 || s->slice_height <= 0) {
229 av_log(avctx, AV_LOG_ERROR,
230 "Buffer stride (%d) or slice height (%d) is invalid\n",
231 s->stride, s->slice_height);
232 goto out;
233 }
234
235 if (OH_AVFormat_GetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, &n)) {
236 s->pix_fmt = n;
237 /* When use output_to_window, the returned format is the memory
238 * layout of hardware frame, not AV_PIXEL_FORMAT_SURFACE_FORMAT as
239 * expected.
240 */
241 if (s->output_to_window)
242 avctx->pix_fmt = AV_PIX_FMT_OHCODEC;
243 else
244 avctx->pix_fmt = ff_oh_pix_to_ff_pix(s->pix_fmt);
245 // Check whether this pixel format is supported
246 if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
247 av_log(avctx, AV_LOG_ERROR, "Unsupported OH_AVPixelFormat %d\n",
248 n);
249 goto out;
250 }
251 } else {
252 av_log(avctx, AV_LOG_ERROR, "Failed to get pixel format\n");
253 goto out;
254 }
255
256 if (OH_AVFormat_GetIntValue(format,
257 OH_MD_KEY_MATRIX_COEFFICIENTS,
258 &n))
259 avctx->colorspace = n;
260 if (OH_AVFormat_GetIntValue(format,
261 OH_MD_KEY_COLOR_PRIMARIES,
262 &n))
263 avctx->color_primaries = n;
264 if (OH_AVFormat_GetIntValue(format,
265 OH_MD_KEY_TRANSFER_CHARACTERISTICS,
266 &n))
267 avctx->color_trc = n;
268 if (OH_AVFormat_GetIntValue(format,
269 OH_MD_KEY_RANGE_FLAG,
270 &n))
271 avctx->color_range = n ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
272
273 if (OH_AVFormat_GetDoubleValue(format, OH_MD_KEY_VIDEO_SAR, &d)) {
274 AVRational sar = av_d2q(d, 4096 * 4);
275 ff_set_sar(avctx, sar);
276 }
277
278 s->got_stream_info = true;
279
280 return;
281out:
282 av_log(avctx, AV_LOG_ERROR, "Invalid format from decoder: %s\n",
283 OH_AVFormat_DumpInfo(format));
284 oh_decode_on_err(codec, AV_ERR_UNKNOWN, userdata);
285}
286
287static void oh_decode_on_need_input(OH_AVCodec *codec, uint32_t index,
288 OH_AVBuffer *buffer, void *userdata)
289{
290 AVCodecContext *avctx = userdata;
291 OHCodecDecContext *s = avctx->priv_data;
292 OHBufferQueueItem item = {
293 index, buffer,
294 };
295
296 ff_mutex_lock(&s->input_mutex);
297 int ret = av_fifo_write(s->input_queue, &item, 1);
298 if (ret >= 0)
299 ff_cond_signal(&s->input_cond);
300 ff_mutex_unlock(&s->input_mutex);
301
302 if (ret < 0)
303 oh_decode_on_err(codec, AV_ERR_NO_MEMORY, userdata);
304}
305
306static void oh_decode_on_output(OH_AVCodec *codec, uint32_t index,
307 OH_AVBuffer *buffer, void *userdata)
308{
309 AVCodecContext *avctx = userdata;
310 OHCodecDecContext *s = avctx->priv_data;
311 OHBufferQueueItem item = {
312 index, buffer,
313 };
314
315 ff_mutex_lock(&s->output_mutex);
316 int ret = av_fifo_write(s->output_queue, &item, 1);
317 if (ret >= 0)
318 ff_cond_signal(&s->output_cond);
319 ff_mutex_unlock(&s->output_mutex);
320
321 if (ret < 0)
322 oh_decode_on_err(codec, AV_ERR_NO_MEMORY, userdata);
323}
324
325static int oh_decode_start(OHCodecDecContext *s, AVCodecContext *avctx)
326{
327 int ret;
328 OH_AVErrCode err;
329 OH_AVCodecCallback cb = {
330 .onError = oh_decode_on_err,
331 .onStreamChanged = oh_decode_on_stream_changed,
332 .onNeedInputBuffer = oh_decode_on_need_input,
333 .onNewOutputBuffer = oh_decode_on_output,
334 };
335
336 err = OH_VideoDecoder_RegisterCallback(s->dec, cb, avctx);
337 if (err != AV_ERR_OK) {
338 ret = ff_oh_err_to_ff_err(err);
339 av_log(avctx, AV_LOG_ERROR, "Register callback failed, %d, %s\n",
340 err, av_err2str(ret));
341 return ret;
342 }
343 err = OH_VideoDecoder_Prepare(s->dec);
344 if (err != AV_ERR_OK) {
345 ret = ff_oh_err_to_ff_err(err);
346 av_log(avctx, AV_LOG_ERROR, "Prepare failed, %d, %s\n",
347 err, av_err2str(ret));
348 return ret;
349 }
350 err = OH_VideoDecoder_Start(s->dec);
351 if (err != AV_ERR_OK) {
352 ret = ff_oh_err_to_ff_err(err);
353 av_log(avctx, AV_LOG_ERROR, "Start failed, %d, %s\n",
354 err, av_err2str(ret));
355 return ret;
356 }
357
358 return 0;
359}
360
361static av_cold int oh_decode_init(AVCodecContext *avctx)
362{
363 OHCodecDecContext *s = avctx->priv_data;
364
365 // Initialize these fields first, so oh_decode_close can destroy them safely
366 ff_mutex_init(&s->input_mutex, NULL);
367 ff_cond_init(&s->input_cond, NULL);
368 ff_mutex_init(&s->output_mutex, NULL);
369 ff_cond_init(&s->output_cond, NULL);
370
371 int ret = oh_decode_create(s, avctx);
372 if (ret < 0)
373 return ret;
374 ret = oh_decode_set_format(s, avctx);
375 if (ret < 0)
376 return ret;
377
378 size_t fifo_size = 16;
379 s->input_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem),
380 AV_FIFO_FLAG_AUTO_GROW);
381 s->output_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem),
382 AV_FIFO_FLAG_AUTO_GROW);
383 if (!s->input_queue || !s->output_queue)
384 return AVERROR(ENOMEM);
385
386 ret = oh_decode_start(s, avctx);
387 if (ret < 0)
388 return ret;
389
390 return 0;
391}
392
393static av_cold int oh_decode_close(AVCodecContext *avctx)
394{
395 OHCodecDecContext *s = avctx->priv_data;
396
397 if (s->dec) {
398 /* Stop but don't destroy dec directly, to keep hardware frames on
399 * the fly valid.
400 */
401 OH_AVErrCode err = OH_VideoDecoder_Stop(s->dec);
402 if (err == AV_ERR_OK)
403 av_log(avctx, AV_LOG_DEBUG, "Stop decoder success\n");
404 else
405 av_log(avctx, AV_LOG_ERROR, "Stop decoder failed, %d, %s\n",
406 err, av_err2str(ff_oh_err_to_ff_err(err)));
407 s->dec = NULL;
408 av_buffer_unref(&s->dec_ref);
409 }
410
411 av_packet_unref(&s->pkt);
412
413 ff_mutex_destroy(&s->input_mutex);
414 ff_cond_destroy(&s->input_cond);
415 av_fifo_freep2(&s->input_queue);
416
417 ff_mutex_destroy(&s->output_mutex);
418 ff_cond_destroy(&s->output_cond);
419 av_fifo_freep2(&s->output_queue);
420
421 return 0;
422}
423
424static void oh_buffer_release(void *opaque, uint8_t *data)
425{
426 if (!opaque)
427 return;
428
429 OHCodecBuffer *buffer = opaque;
430
431 if (!buffer->dec_ref) {
432 av_free(buffer);
433 return;
434 }
435
436 if (buffer->buffer) {
437 OH_AVCodec *dec = (OH_AVCodec *)buffer->dec_ref->data;
438 OH_AVCodecBufferAttr attr;
439 OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(buffer->buffer, &attr);
440 if (err == AV_ERR_OK && !(attr.flags & AVCODEC_BUFFER_FLAGS_DISCARD))
441 OH_VideoDecoder_RenderOutputBuffer(dec, buffer->index);
442 else
443 OH_VideoDecoder_FreeOutputBuffer(dec, buffer->index);
444 }
445
446 av_buffer_unref(&buffer->dec_ref);
447 av_free(buffer);
448}
449
450static int oh_decode_wrap_hw_buffer(AVCodecContext *avctx, AVFrame *frame,
451 OHBufferQueueItem *output,
452 const OH_AVCodecBufferAttr *attr)
453{
454 OHCodecDecContext *s = avctx->priv_data;
455
456 frame->width = s->width;
457 frame->height = s->height;
458 int ret = ff_decode_frame_props(avctx, frame);
459 if (ret < 0)
460 return ret;
461
462 frame->format = AV_PIX_FMT_OHCODEC;
463 OHCodecBuffer *buffer = av_mallocz(sizeof(*buffer));
464 if (!buffer)
465 return AVERROR(ENOMEM);
466
467 buffer->dec_ref = av_buffer_ref(s->dec_ref);
468 if (!buffer->dec_ref) {
469 oh_buffer_release(buffer, NULL);
470 return AVERROR(ENOMEM);
471 }
472
473 buffer->index = output->index;
474 buffer->buffer = output->buffer;
475 frame->buf[0] = av_buffer_create((uint8_t *)buffer->buffer, 1,
476 oh_buffer_release,
477 buffer, AV_BUFFER_FLAG_READONLY);
478 if (!frame->buf[0]) {
479 oh_buffer_release(buffer, NULL);
480 return AVERROR(ENOMEM);
481 }
482 // Point to OH_AVBuffer
483 frame->data[3] = frame->buf[0]->data;
484 frame->pts = av_rescale_q(attr->pts, AV_TIME_BASE_Q, avctx->pkt_timebase);
485 frame->pkt_dts = AV_NOPTS_VALUE;
486
487 return 0;
488}
489
490static int oh_decode_wrap_sw_buffer(AVCodecContext *avctx, AVFrame *frame,
491 OHBufferQueueItem *output,
492 const OH_AVCodecBufferAttr *attr)
493{
494 OHCodecDecContext *s = avctx->priv_data;
495
496 frame->format = avctx->pix_fmt;
497 frame->width = s->width;
498 frame->height = s->height;
499 int ret = ff_get_buffer(avctx, frame, 0);
500 if (ret < 0)
501 return ret;
502
503 frame->pts = av_rescale_q(attr->pts, AV_TIME_BASE_Q, avctx->pkt_timebase);
504 frame->pkt_dts = AV_NOPTS_VALUE;
505
506 uint8_t *p = OH_AVBuffer_GetAddr(output->buffer);
507 if (!p) {
508 av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer addr\n");
509 return AVERROR_EXTERNAL;
510 }
511
512 uint8_t *src[4] = {0};
513 int src_linesizes[4] = {0};
514
515 ret = av_image_fill_linesizes(src_linesizes, frame->format, s->stride);
516 if (ret < 0)
517 return ret;
518 ret = av_image_fill_pointers(src, frame->format, s->slice_height, p,
519 src_linesizes);
520 if (ret < 0)
521 return ret;
522 av_image_copy2(frame->data, frame->linesize, src, src_linesizes,
523 frame->format, frame->width, frame->height);
524
525 OH_AVErrCode err = OH_VideoDecoder_FreeOutputBuffer(s->dec, output->index);
526 if (err != AV_ERR_OK) {
527 ret = ff_oh_err_to_ff_err(err);
528 av_log(avctx, AV_LOG_ERROR, "FreeOutputBuffer failed, %d, %s\n", err,
529 av_err2str(ret));
530 return ret;
531 }
532
533 return 0;
534}
535
536static int oh_decode_output_frame(AVCodecContext *avctx, AVFrame *frame,
537 OHBufferQueueItem *output)
538{
539 OHCodecDecContext *s = avctx->priv_data;
540 OH_AVCodecBufferAttr attr;
541
542 OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(output->buffer, &attr);
543 if (err != AV_ERR_OK)
544 return ff_oh_err_to_ff_err(err);
545
546 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
547 av_log(avctx, AV_LOG_DEBUG, "Buffer flag eos\n");
548 OH_VideoDecoder_FreeOutputBuffer(s->dec, output->index);
549 return AVERROR_EOF;
550 }
551
552 if (!s->got_stream_info) {
553 // This shouldn't happen, add a warning message.
554 av_log(avctx, AV_LOG_WARNING,
555 "decoder didn't notify stream info, try get format explicitly\n");
556
557 OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(s->dec);
558 if (!format) {
559 av_log(avctx, AV_LOG_ERROR, "GetOutputDescription failed\n");
560 return AVERROR_EXTERNAL;
561 }
562
563 oh_decode_on_stream_changed(s->dec, format, avctx);
564 OH_AVFormat_Destroy(format);
565 if (!s->got_stream_info)
566 return AVERROR_EXTERNAL;
567 }
568
569 if (s->output_to_window)
570 return oh_decode_wrap_hw_buffer(avctx, frame, output, &attr);
571 return oh_decode_wrap_sw_buffer(avctx, frame, output, &attr);
572}
573
574static int oh_decode_send_pkt(AVCodecContext *avctx, OHBufferQueueItem *input)
575{
576 OHCodecDecContext *s = avctx->priv_data;
577 OH_AVErrCode err;
578 int ret;
579
580 if (!s->pkt.size && !s->eof_sent) {
581 OH_AVCodecBufferAttr attr = {
582 .flags = AVCODEC_BUFFER_FLAGS_EOS,
583 };
584 err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr);
585 if (err != AV_ERR_OK)
586 return ff_oh_err_to_ff_err(err);
587 err = OH_VideoDecoder_PushInputBuffer(s->dec, input->index);
588 if (err != AV_ERR_OK)
589 return ff_oh_err_to_ff_err(err);
590 s->eof_sent = true;
591 return 0;
592 }
593
594 uint8_t *p = OH_AVBuffer_GetAddr(input->buffer);
595 int32_t n = OH_AVBuffer_GetCapacity(input->buffer);
596 if (!p || n <= 0) {
597 av_log(avctx, AV_LOG_ERROR,
598 "Failed to get buffer addr (%p) or capacity (%d)\n",
599 p, n);
600 return AVERROR_EXTERNAL;
601 }
602 n = FFMIN(s->pkt.size, n);
603 memcpy(p, s->pkt.data, n);
604
605 OH_AVCodecBufferAttr attr = {
606 .size = n,
607 .offset = 0,
608 .pts = av_rescale_q(s->pkt.pts, avctx->pkt_timebase,
609 AV_TIME_BASE_Q),
610 .flags = (s->pkt.flags & AV_PKT_FLAG_KEY)
611 ? AVCODEC_BUFFER_FLAGS_SYNC_FRAME : 0,
612 };
613
614 err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr);
615 if (err != AV_ERR_OK) {
616 ret = ff_oh_err_to_ff_err(err);
617 return ret;
618 }
619 err = OH_VideoDecoder_PushInputBuffer(s->dec, input->index);
620 if (err != AV_ERR_OK) {
621 ret = ff_oh_err_to_ff_err(err);
622 av_log(avctx, AV_LOG_ERROR, "Push input buffer failed, %d, %s\n",
623 err, av_err2str(ret));
624 return ret;
625 }
626
627 if (n < s->pkt.size) {
628 s->pkt.size -= n;
629 s->pkt.data += n;
630 } else {
631 av_packet_unref(&s->pkt);
632 }
633
634 return 0;
635}
636
637static int oh_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame)
638{
639 OHCodecDecContext *s = avctx->priv_data;
640
641 while (1) {
642 OHBufferQueueItem buffer = {0};
643 int ret;
644
645 // Try get output
646 ff_mutex_lock(&s->output_mutex);
647 while (!s->decode_status) {
648 if (av_fifo_read(s->output_queue, &buffer, 1) >= 0)
649 break;
650 // Only wait after send EOF
651 if (s->eof_sent && !s->decode_status)
652 ff_cond_wait(&s->output_cond, &s->output_mutex);
653 else
654 break;
655 }
656
657 ret = s->decode_status;
658 ff_mutex_unlock(&s->output_mutex);
659
660 // Got a frame
661 if (buffer.buffer)
662 return oh_decode_output_frame(avctx, frame, &buffer);
663 if (ret < 0)
664 return ret;
665
666 if (!s->pkt.size) {
667 /* fetch new packet or eof */
668 ret = ff_decode_get_packet(avctx, &s->pkt);
669 if (ret < 0 && ret != AVERROR_EOF)
670 return ret;
671 }
672
673 // Wait input buffer
674 ff_mutex_lock(&s->input_mutex);
675 while (!s->decode_status) {
676 if (av_fifo_read(s->input_queue, &buffer, 1) >= 0)
677 break;
678 ff_cond_wait(&s->input_cond, &s->input_mutex);
679 }
680
681 ret = s->decode_status;
682 ff_mutex_unlock(&s->input_mutex);
683
684 if (ret < 0)
685 return ret;
686
687 ret = oh_decode_send_pkt(avctx, &buffer);
688 if (ret < 0)
689 return ret;
690 }
691
692 return AVERROR(EAGAIN);
693}
694
695static void oh_decode_flush(AVCodecContext *avctx)
696{
697 OHCodecDecContext *s = avctx->priv_data;
698
699 OH_VideoDecoder_Flush(s->dec);
700
701 ff_mutex_lock(&s->input_mutex);
702 ff_mutex_lock(&s->output_mutex);
703 av_fifo_reset2(s->input_queue);
704 av_fifo_reset2(s->output_queue);
705 s->decode_status = 0;
706 s->eof_sent = false;
707 ff_mutex_unlock(&s->output_mutex);
708 ff_mutex_unlock(&s->input_mutex);
709
710 OH_VideoDecoder_Start(s->dec);
711}
712
713static const AVCodecHWConfigInternal *const oh_hw_configs[] = {
714 &(const AVCodecHWConfigInternal) {
715 .public = {
716 .pix_fmt = AV_PIX_FMT_OHCODEC,
717 .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC |
718 AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
719 .device_type = AV_HWDEVICE_TYPE_OHCODEC,
720 },
721 .hwaccel = NULL,
722 },
723 NULL
724};
725
726#define OFFSET(x) offsetof(OHCodecDecContext, x)
727#define VD (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM)
728static const AVOption ohcodec_vdec_options[] = {
729 {"codec_name", "Select codec by name",
730 OFFSET(name), AV_OPT_TYPE_STRING, .flags = VD},
731 {"allow_sw", "Allow software decoding",
732 OFFSET(allow_sw), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD},
733 {NULL}
734};
735
736#define DECLARE_OHCODEC_VCLASS(short_name) \
737 static const AVClass short_name##_oh_dec_class = { \
738 .class_name = #short_name "_ohcodec", \
739 .item_name = av_default_item_name, \
740 .option = ohcodec_vdec_options, \
741 .version = LIBAVUTIL_VERSION_INT, \
742 };
743
744#define DECLARE_OHCODEC_VDEC(short_name, full_name, codec_id, bsf) \
745 DECLARE_OHCODEC_VCLASS(short_name) \
746 const FFCodec ff_##short_name##_oh_decoder = { \
747 .p.name = #short_name "_ohcodec", \
748 CODEC_LONG_NAME(full_name " OpenHarmony Codec"), \
749 .p.type = AVMEDIA_TYPE_VIDEO, \
750 .p.id = codec_id, \
751 .p.priv_class = &short_name##_oh_dec_class, \
752 .priv_data_size = sizeof(OHCodecDecContext), \
753 .init = oh_decode_init, \
754 FF_CODEC_RECEIVE_FRAME_CB(oh_decode_receive_frame), \
755 .flush = oh_decode_flush, \
756 .close = oh_decode_close, \
757 .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | \
758 AV_CODEC_CAP_HARDWARE, \
759 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \
760 .bsfs = bsf, \
761 .hw_configs = oh_hw_configs, \
762 .p.wrapper_name = "ohcodec", \
763 };
764
765#if CONFIG_H264_OH_DECODER
766DECLARE_OHCODEC_VDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb")
767#endif
768
769#if CONFIG_HEVC_OH_DECODER
770DECLARE_OHCODEC_VDEC(hevc, "H.265", AV_CODEC_ID_HEVC, "hevc_mp4toannexb")
771#endif
libavcodec/version.h+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
29 29
30#include "version_major.h"30#include "version_major.h"
31 31
32#define LIBAVCODEC_VERSION_MINOR 632#define LIBAVCODEC_VERSION_MINOR 7
33#define LIBAVCODEC_VERSION_MICRO 10033#define LIBAVCODEC_VERSION_MICRO 100
34 34
35#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \35#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t