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
34113411 h264_mmal_decoder_deps="mmal"
34123412 h264_nvenc_encoder_deps="nvenc"
34133413 h264_nvenc_encoder_select="atsc_a53"
3414+h264_oh_decoder_deps="ohcodec"
3415+h264_oh_decoder_select="h264_mp4toannexb_bsf"
34143416 h264_omx_encoder_deps="omx"
34153417 h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec"
34163418 h264_qsv_encoder_select="atsc_a53 qsvenc"
@@ -3433,6 +3435,8 @@ hevc_mediacodec_encoder_select="extract_extradata_bsf hevc_metadata" · 16 unmodified lines
34333435 hevc_mf_encoder_deps="mediafoundation"
34343436 hevc_nvenc_encoder_deps="nvenc"
34353437 hevc_nvenc_encoder_select="atsc_a53"
3438+hevc_oh_decoder_deps="ohcodec"
3439+hevc_oh_decoder_select="hevc_mp4toannexb_bsf"
34363440 hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec"
34373441 hevc_qsv_encoder_select="hevcparse qsvenc"
34383442 hevc_rkmpp_decoder_deps="rkmpp"
libavcodec/Makefile+3−0
@@ -428,6 +428,7 @@ OBJS-$(CONFIG_H264_MEDIACODEC_ENCODER) += mediacodecenc.o · 427 unmodified lines
428428 OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o
429429 OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
430430 OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o
431+OBJS-$(CONFIG_H264_OH_DECODER) += ohcodec.o ohdec.o
431432 OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o
432433 OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o
433434 OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o
@@ -456,6 +457,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o · 22 unmodified lines
456457 OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o
457458 OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o
458459 OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o
460+OBJS-$(CONFIG_HEVC_OH_DECODER) += ohcodec.o ohdec.o
459461 OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o
460462 OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o
461463 OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o
@@ -1314,6 +1316,7 @@ SKIPHEADERS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.h mediacodec_surf · 852 unmodified lines
13141316 SKIPHEADERS-$(CONFIG_MEDIAFOUNDATION) += mf_utils.h
13151317 SKIPHEADERS-$(CONFIG_NVDEC) += nvdec.h
13161318 SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h
1319+SKIPHEADERS-$(CONFIG_OHCODEC) += ohcodec.h
13171320 SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h
13181321 SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h
13191322 SKIPHEADERS-$(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
860860 extern const FFCodec ff_h264_cuvid_decoder;
861861 extern const FFCodec ff_h264_mf_encoder;
862862 extern const FFCodec ff_h264_nvenc_encoder;
863+extern const FFCodec ff_h264_oh_decoder;
863864 extern const FFCodec ff_h264_omx_encoder;
864865 extern const FFCodec ff_h264_qsv_encoder;
865866 extern const FFCodec ff_h264_v4l2m2m_encoder;
@@ -874,6 +875,7 @@ extern const FFCodec ff_hevc_mediacodec_decoder; · 8 unmodified lines
874875 extern const FFCodec ff_hevc_mediacodec_encoder;
875876 extern const FFCodec ff_hevc_mf_encoder;
876877 extern const FFCodec ff_hevc_nvenc_encoder;
878+extern const FFCodec ff_hevc_oh_decoder;
877879 extern const FFCodec ff_hevc_qsv_encoder;
878880 extern const FFCodec ff_hevc_v4l2m2m_encoder;
879881 extern 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+
25+int 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+
53+static 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+
63+enum 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+
33+typedef struct OHBufferQueueItem {
34+ uint32_t index;
35+ OH_AVBuffer *buffer;
36+} OHBufferQueueItem;
37+
38+int ff_oh_err_to_ff_err(OH_AVErrCode err);
39+
40+static 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+
54+enum 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+
40+typedef 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+
74+typedef struct OHCodecBuffer {
75+ uint32_t index;
76+ OH_AVBuffer *buffer;
77+ AVBufferRef *dec_ref;
78+} OHCodecBuffer;
79+
80+static 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+
91+static 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+
133+static 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+
191+static 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+
208+static 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;
281+out:
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+
287+static 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+
306+static 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+
325+static 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+
361+static 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+
393+static 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+
424+static 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+
450+static 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+
490+static 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+
536+static 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+
574+static 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+
637+static 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+
695+static 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+
713+static 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)
728+static 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
766+DECLARE_OHCODEC_VDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb")
767+#endif
768+
769+#if CONFIG_HEVC_OH_DECODER
770+DECLARE_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
2929
3030 #include "version_major.h"
3131
32−#define LIBAVCODEC_VERSION_MINOR 6
32+#define LIBAVCODEC_VERSION_MINOR 7
3333 #define LIBAVCODEC_VERSION_MICRO 100
3434
3535 #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