History

avcodec/ohenc: Add h264/hevc OpenHarmony encoders

Zhao Zhili committed 1 year ago

Commit fa0080b1 parent e7f44f88 files · +732 −3Browse files

Unified · Split

8 files
  1. Changelog +1 −0
  2. configure +5 −2
  3. libavcodec/Makefile +2 −0
  4. libavcodec/allcodecs.c +2 −0
  5. libavcodec/ohcodec.c +8 −0
  6. libavcodec/ohcodec.h +1 −0
  7. libavcodec/ohenc.c +712 −0
  8. libavcodec/version.h +1 −1
Changelog+1−0
@@ -23,6 +23,7 @@ version <next>: · 22 unmodified lines
23- pad_cuda filter23- pad_cuda filter
24- Sanyo LD-ADPCM decoder24- Sanyo LD-ADPCM decoder
25- APV in MP4/ISOBMFF demuxing25- APV in MP4/ISOBMFF demuxing
26- OpenHarmony hardware decoder/encoder
26 27
27 28
28version 7.1:29version 7.1:
configure+5−2
@@ -3413,6 +3413,7 @@ h264_nvenc_encoder_deps="nvenc" · 3412 unmodified lines
3413h264_nvenc_encoder_select="atsc_a53"3413h264_nvenc_encoder_select="atsc_a53"
3414h264_oh_decoder_deps="ohcodec"3414h264_oh_decoder_deps="ohcodec"
3415h264_oh_decoder_select="h264_mp4toannexb_bsf"3415h264_oh_decoder_select="h264_mp4toannexb_bsf"
3416h264_oh_encoder_deps="ohcodec"
3416h264_omx_encoder_deps="omx"3417h264_omx_encoder_deps="omx"
3417h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec"3418h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec"
3418h264_qsv_encoder_select="atsc_a53 qsvenc"3419h264_qsv_encoder_select="atsc_a53 qsvenc"
@@ -3437,6 +3438,7 @@ hevc_nvenc_encoder_deps="nvenc" · 18 unmodified lines
3437hevc_nvenc_encoder_select="atsc_a53"3438hevc_nvenc_encoder_select="atsc_a53"
3438hevc_oh_decoder_deps="ohcodec"3439hevc_oh_decoder_deps="ohcodec"
3439hevc_oh_decoder_select="hevc_mp4toannexb_bsf"3440hevc_oh_decoder_select="hevc_mp4toannexb_bsf"
3441hevc_oh_encoder_deps="ohcodec"
3440hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec"3442hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec"
3441hevc_qsv_encoder_select="hevcparse qsvenc"3443hevc_qsv_encoder_select="hevcparse qsvenc"
3442hevc_rkmpp_decoder_deps="rkmpp"3444hevc_rkmpp_decoder_deps="rkmpp"
@@ -7177,8 +7179,9 @@ enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_co · 3734 unmodified lines
7177 check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host; } ||7179 check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host; } ||
7178 die "ERROR: mmal not found" &&7180 die "ERROR: mmal not found" &&
7179 check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; }7181 check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; }
7180enabled ohcodec && { check_lib ohcodec "multimedia/player_framework/native_avcodec_videodecoder.h" \7182enabled ohcodec && { check_lib ohcodec "multimedia/player_framework/native_avcodec_videodecoder.h multimedia/player_framework/native_avcodec_videoencoder.h" \
7181 OH_VideoDecoder_CreateByName -lnative_media_codecbase -lnative_media_core -lnative_media_vdec ||7183 "OH_VideoDecoder_CreateByName OH_VideoEncoder_CreateByName" \
7184 -lnative_media_vdec -lnative_media_venc -lnative_media_codecbase -lnative_media_core -lnative_window ||
7182 die "ERROR: missing native_media libs"; }7185 die "ERROR: missing native_media libs"; }
7183enabled openal && { check_pkg_config openal "openal >= 1.1" "AL/al.h" alGetError ||7186enabled openal && { check_pkg_config openal "openal >= 1.1" "AL/al.h" alGetError ||
7184 { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do7187 { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do
libavcodec/Makefile+2−0
@@ -429,6 +429,7 @@ OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o · 428 unmodified lines
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.o431OBJS-$(CONFIG_H264_OH_DECODER) += ohcodec.o ohdec.o
432OBJS-$(CONFIG_H264_OH_ENCODER) += ohcodec.o ohenc.o
432OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o433OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o
433OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o434OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o
434OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o435OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o
@@ -458,6 +459,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o · 23 unmodified lines
458OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o459OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o
459OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o460OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o
460OBJS-$(CONFIG_HEVC_OH_DECODER) += ohcodec.o ohdec.o461OBJS-$(CONFIG_HEVC_OH_DECODER) += ohcodec.o ohdec.o
462OBJS-$(CONFIG_HEVC_OH_ENCODER) += ohcodec.o ohenc.o
461OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o463OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o
462OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o464OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o
463OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o465OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o
libavcodec/allcodecs.c+2−0
@@ -861,6 +861,7 @@ extern const FFCodec ff_h264_cuvid_decoder; · 860 unmodified lines
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_oh_decoder;
864extern const FFCodec ff_h264_oh_encoder;
864extern const FFCodec ff_h264_omx_encoder;865extern const FFCodec ff_h264_omx_encoder;
865extern const FFCodec ff_h264_qsv_encoder;866extern const FFCodec ff_h264_qsv_encoder;
866extern const FFCodec ff_h264_v4l2m2m_encoder;867extern const FFCodec ff_h264_v4l2m2m_encoder;
@@ -876,6 +877,7 @@ extern const FFCodec ff_hevc_mediacodec_encoder; · 9 unmodified lines
876extern const FFCodec ff_hevc_mf_encoder;877extern const FFCodec ff_hevc_mf_encoder;
877extern const FFCodec ff_hevc_nvenc_encoder;878extern const FFCodec ff_hevc_nvenc_encoder;
878extern const FFCodec ff_hevc_oh_decoder;879extern const FFCodec ff_hevc_oh_decoder;
880extern const FFCodec ff_hevc_oh_encoder;
879extern const FFCodec ff_hevc_qsv_encoder;881extern const FFCodec ff_hevc_qsv_encoder;
880extern const FFCodec ff_hevc_v4l2m2m_encoder;882extern const FFCodec ff_hevc_v4l2m2m_encoder;
881extern const FFCodec ff_hevc_vaapi_encoder;883extern const FFCodec ff_hevc_vaapi_encoder;
libavcodec/ohcodec.c+8−0
@@ -69,3 +69,11 @@ enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix) · 68 unmodified lines
69 return AV_PIX_FMT_NONE;69 return AV_PIX_FMT_NONE;
70}70}
71 71
72int ff_oh_pix_from_ff_pix(enum AVPixelFormat pix)
73{
74 for (size_t i = 0; i < FF_ARRAY_ELEMS(oh_pix_map); i++)
75 if (oh_pix_map[i].pix == pix)
76 return oh_pix_map[i].oh_pix;
77
78 return 0;
79}
libavcodec/ohcodec.h+1−0
@@ -52,5 +52,6 @@ static inline const char *ff_oh_mime(enum AVCodecID codec_id, void *log) · 51 unmodified lines
52}52}
53 53
54enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix);54enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix);
55int ff_oh_pix_from_ff_pix(enum AVPixelFormat pix);
55 56
56#endif57#endif
libavcodec/ohenc.c+712−0
@@ -0,0 +1,712 @@
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_videoencoder.h>
26#include <native_window/external_window.h>
27
28#include "libavutil/fifo.h"
29#include "libavutil/hwcontext_oh.h"
30#include "libavutil/imgutils.h"
31#include "libavutil/mem.h"
32#include "libavutil/opt.h"
33#include "libavutil/thread.h"
34
35#include "avcodec.h"
36#include "codec_internal.h"
37#include "encode.h"
38#include "hwconfig.h"
39#include "ohcodec.h"
40
41typedef struct OHCodecEncContext {
42 AVClass *avclass;
43 OH_AVCodec *enc;
44
45 AVMutex input_mutex;
46 AVCond input_cond;
47 AVFifo *input_queue;
48
49 AVMutex output_mutex;
50 AVCond output_cond;
51 AVFifo *output_queue;
52
53 AVFrame *frame;
54 uint8_t *extradata;
55 int extradata_size;
56
57 int encode_status;
58 bool eof_sent;
59
60 bool got_stream_info;
61 int stride;
62 int slice_height;
63
64 OHNativeWindow *native_window;
65 char *name;
66 int allow_sw;
67 int bitrate_mode;
68} OHCodecEncContext;
69
70static const enum AVPixelFormat ohcodec_pix_fmts[] = {
71 AV_PIX_FMT_OHCODEC,
72 AV_PIX_FMT_NV12,
73 AV_PIX_FMT_NONE
74};
75
76static int oh_encode_create(OHCodecEncContext *s, AVCodecContext *avctx)
77{
78 const char *name = s->name;
79
80 if (!name) {
81 const char *mime = ff_oh_mime(avctx->codec_id, avctx);
82 if (!mime)
83 return AVERROR_BUG;
84 OH_AVCapability *cap = OH_AVCodec_GetCapabilityByCategory(mime, true, HARDWARE);
85 if (!cap) {
86 if (!s->allow_sw) {
87 av_log(avctx, AV_LOG_ERROR, "Failed to get hardware codec %s\n", mime);
88 return AVERROR_EXTERNAL;
89 }
90 av_log(avctx, AV_LOG_WARNING,
91 "Failed to get hardware codec %s, try software backend\n", mime);
92 cap = OH_AVCodec_GetCapabilityByCategory(mime, true, SOFTWARE);
93 if (!cap) {
94 av_log(avctx, AV_LOG_ERROR, "Failed to get software codec %s\n", mime);
95 return AVERROR_EXTERNAL;
96 }
97 }
98 name = OH_AVCapability_GetName(cap);
99 if (!name)
100 return AVERROR_EXTERNAL;
101 }
102
103 s->enc = OH_VideoEncoder_CreateByName(name);
104 if (!s->enc) {
105 av_log(avctx, AV_LOG_ERROR, "Create encoder with name %s failed\n", name);
106 return AVERROR_EXTERNAL;
107 }
108 av_log(avctx, AV_LOG_DEBUG, "Create encoder %s success\n", name);
109
110 return 0;
111}
112
113static int oh_encode_set_format(OHCodecEncContext *s, AVCodecContext *avctx)
114{
115 int ret;
116
117 OH_AVFormat *format = OH_AVFormat_Create();
118 if (!format)
119 return AVERROR(ENOMEM);
120
121 bool b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, avctx->width);
122 b = b && OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, avctx->height);
123 if (!b) {
124 av_log(avctx, AV_LOG_ERROR, "Set width/height (%dx%d) failed\n",
125 avctx->width, avctx->height);
126 ret = AVERROR_EXTERNAL;
127 goto out;
128 }
129 if (avctx->framerate.num && avctx->framerate.den)
130 OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE,
131 av_q2d(avctx->framerate));
132 int pix = ff_oh_pix_from_ff_pix(avctx->pix_fmt);
133 if (!pix) {
134 ret = AVERROR_BUG;
135 goto out;
136 }
137 b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, pix);
138 if (!b) {
139 av_log(avctx, AV_LOG_ERROR, "Set pixel format to %d failed\n", pix);
140 ret = AVERROR_EXTERNAL;
141 goto out;
142 }
143
144 if (s->bitrate_mode != -1) {
145 b = OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, s->bitrate_mode);
146 if (!b) {
147 av_log(avctx, AV_LOG_ERROR, "Set bitrate mode to %d failed\n",
148 s->bitrate_mode);
149 ret = AVERROR_EXTERNAL;
150 goto out;
151 }
152 }
153 OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, avctx->bit_rate);
154
155 if (avctx->gop_size > 0) {
156 if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
157 // In milliseconds
158 int gop = av_rescale_q(avctx->gop_size,
159 av_make_q(avctx->framerate.den,
160 avctx->framerate.num),
161 av_make_q(1, 1000));
162 OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, gop);
163 } else {
164 av_log(avctx, AV_LOG_WARNING, "Skip setting gop without framerate\n");
165 }
166 } else if (!avctx->gop_size) {
167 // All frames are key frame
168 OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, 0);
169 } else if (avctx->gop_size == -1) {
170 // Infinite gop
171 OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, -1);
172 }
173
174 OH_AVErrCode err = OH_VideoEncoder_Configure(s->enc, format);
175 if (err != AV_ERR_OK) {
176 ret = ff_oh_err_to_ff_err(err);
177 av_log(avctx, AV_LOG_ERROR, "Decoder configure failed, %d, %s\n",
178 err, av_err2str(ret));
179 goto out;
180 }
181
182 if (avctx->pix_fmt == AV_PIX_FMT_OHCODEC) {
183 if (avctx->hw_device_ctx) {
184 av_log(avctx, AV_LOG_ERROR,
185 "ohcodec can only export native window via hw device, "
186 "doesn't support import hw device\n");
187 ret = AVERROR(EINVAL);
188 goto out;
189 }
190
191 err = OH_VideoEncoder_GetSurface(s->enc, &s->native_window);
192 if (err != AV_ERR_OK) {
193 ret = ff_oh_err_to_ff_err(err);
194 av_log(avctx, AV_LOG_ERROR, "Get surface failed, %d, %s\n",
195 err, av_err2str(ret));
196 goto out;
197 }
198 av_log(avctx, AV_LOG_INFO, "Native window %p\n", s->native_window);
199
200 ret = av_hwdevice_ctx_create(&avctx->hw_device_ctx,
201 AV_HWDEVICE_TYPE_OHCODEC, NULL, NULL, 0);
202 if (ret < 0)
203 goto out;
204
205 AVOHCodecDeviceContext *dev = ((AVHWDeviceContext *)avctx->hw_device_ctx->data)->hwctx;
206 dev->native_window = s->native_window;
207 }
208
209 return 0;
210out:
211 OH_AVFormat_Destroy(format);
212 return ret;
213}
214
215static void oh_encode_on_err(OH_AVCodec *codec, int32_t err, void *userdata)
216{
217 AVCodecContext *avctx = userdata;
218 OHCodecEncContext *s = avctx->priv_data;
219
220 // Careful on the lock order.
221 // Always lock input first.
222 ff_mutex_lock(&s->input_mutex);
223 ff_mutex_lock(&s->output_mutex);
224 s->encode_status = ff_oh_err_to_ff_err(err);
225 ff_mutex_unlock(&s->output_mutex);
226 ff_mutex_unlock(&s->input_mutex);
227
228 ff_cond_signal(&s->output_cond);
229 ff_cond_signal(&s->input_cond);
230}
231
232static void oh_encode_on_stream_changed(OH_AVCodec *codec, OH_AVFormat *format,
233 void *userdata)
234{
235 AVCodecContext *avctx = userdata;
236 OHCodecEncContext *s = avctx->priv_data;
237
238 if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_STRIDE, &s->stride))
239 s->stride = avctx->width;
240 if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_VIDEO_SLICE_HEIGHT, &s->slice_height))
241 s->slice_height = avctx->height;
242
243 s->got_stream_info = true;
244}
245
246static void oh_encode_on_need_input(OH_AVCodec *codec, uint32_t index,
247 OH_AVBuffer *buffer, void *userdata)
248{
249 AVCodecContext *avctx = userdata;
250 OHCodecEncContext *s = avctx->priv_data;
251 OHBufferQueueItem item = {
252 index, buffer,
253 };
254
255 ff_mutex_lock(&s->input_mutex);
256 int ret = av_fifo_write(s->input_queue, &item, 1);
257 if (ret >= 0)
258 ff_cond_signal(&s->input_cond);
259 ff_mutex_unlock(&s->input_mutex);
260
261 if (ret < 0)
262 oh_encode_on_err(codec, AV_ERR_NO_MEMORY, userdata);
263}
264
265static void oh_encode_on_output(OH_AVCodec *codec, uint32_t index,
266 OH_AVBuffer *buffer, void *userdata)
267{
268 AVCodecContext *avctx = userdata;
269 OHCodecEncContext *s = avctx->priv_data;
270 OHBufferQueueItem item = {
271 index, buffer,
272 };
273
274 ff_mutex_lock(&s->output_mutex);
275 int ret = av_fifo_write(s->output_queue, &item, 1);
276 if (ret >= 0)
277 ff_cond_signal(&s->output_cond);
278 ff_mutex_unlock(&s->output_mutex);
279
280 if (ret < 0)
281 oh_encode_on_err(codec, AV_ERR_NO_MEMORY, userdata);
282}
283
284static int oh_encode_start(OHCodecEncContext *s, AVCodecContext *avctx)
285{
286 int ret;
287 OH_AVErrCode err;
288 OH_AVCodecCallback cb = {
289 .onError = oh_encode_on_err,
290 .onStreamChanged = oh_encode_on_stream_changed,
291 .onNeedInputBuffer = oh_encode_on_need_input,
292 .onNewOutputBuffer = oh_encode_on_output,
293 };
294
295 err = OH_VideoEncoder_RegisterCallback(s->enc, cb, avctx);
296 if (err != AV_ERR_OK) {
297 ret = ff_oh_err_to_ff_err(err);
298 av_log(avctx, AV_LOG_ERROR, "Register callback failed, %d, %s\n",
299 err, av_err2str(ret));
300 return ret;
301 }
302 err = OH_VideoEncoder_Prepare(s->enc);
303 if (err != AV_ERR_OK) {
304 ret = ff_oh_err_to_ff_err(err);
305 av_log(avctx, AV_LOG_ERROR, "Prepare failed, %d, %s\n",
306 err, av_err2str(ret));
307 return ret;
308 }
309 err = OH_VideoEncoder_Start(s->enc);
310 if (err != AV_ERR_OK) {
311 ret = ff_oh_err_to_ff_err(err);
312 av_log(avctx, AV_LOG_ERROR, "Start failed, %d, %s\n",
313 err, av_err2str(ret));
314 return ret;
315 }
316
317 return 0;
318}
319
320static av_cold int oh_encode_init(AVCodecContext *avctx)
321{
322 OHCodecEncContext *s = avctx->priv_data;
323
324 // Initialize these fields first, so oh_decode_close can destroy them safely
325 ff_mutex_init(&s->input_mutex, NULL);
326 ff_cond_init(&s->input_cond, NULL);
327 ff_mutex_init(&s->output_mutex, NULL);
328 ff_cond_init(&s->output_cond, NULL);
329
330 int ret = oh_encode_create(s, avctx);
331 if (ret < 0)
332 return ret;
333 ret = oh_encode_set_format(s, avctx);
334 if (ret < 0)
335 return ret;
336
337 size_t fifo_size = 16;
338 s->input_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem),
339 AV_FIFO_FLAG_AUTO_GROW);
340 s->output_queue = av_fifo_alloc2(fifo_size, sizeof(OHBufferQueueItem),
341 AV_FIFO_FLAG_AUTO_GROW);
342 s->frame = av_frame_alloc();
343 if (!s->input_queue || !s->output_queue || !s->frame)
344 return AVERROR(ENOMEM);
345
346 ret = oh_encode_start(s, avctx);
347 if (ret < 0)
348 return ret;
349
350 return 0;
351}
352
353static av_cold int oh_encode_close(AVCodecContext *avctx)
354{
355 OHCodecEncContext *s = avctx->priv_data;
356
357 if (s->enc) {
358 if (s->native_window) {
359 OH_NativeWindow_DestroyNativeWindow(s->native_window);
360 s->native_window = NULL;
361 }
362 OH_VideoEncoder_Stop(s->enc);
363 OH_AVErrCode err = OH_VideoEncoder_Destroy(s->enc);
364 if (err == AV_ERR_OK)
365 av_log(avctx, AV_LOG_DEBUG, "Destroy encoder success\n");
366 else
367 av_log(avctx, AV_LOG_ERROR, "Destroy decoder failed, %d, %s\n",
368 err, av_err2str(ff_oh_err_to_ff_err(err)));
369 s->enc = NULL;
370 }
371
372 av_freep(&s->extradata);
373 av_frame_free(&s->frame);
374
375 ff_mutex_destroy(&s->input_mutex);
376 ff_cond_destroy(&s->input_cond);
377 av_fifo_freep2(&s->input_queue);
378
379 ff_mutex_destroy(&s->output_mutex);
380 ff_cond_destroy(&s->output_cond);
381 av_fifo_freep2(&s->output_queue);
382
383 return 0;
384}
385
386static int oh_encode_output_packet(AVCodecContext *avctx, AVPacket *pkt,
387 OHBufferQueueItem *output)
388{
389 OHCodecEncContext *s = avctx->priv_data;
390 uint8_t *p;
391 OH_AVCodecBufferAttr attr;
392 int ret;
393
394 OH_AVErrCode err = OH_AVBuffer_GetBufferAttr(output->buffer, &attr);
395 if (err != AV_ERR_OK) {
396 ret = ff_oh_err_to_ff_err(err);
397 goto out;
398 }
399 if (attr.flags & AVCODEC_BUFFER_FLAGS_EOS) {
400 av_log(avctx, AV_LOG_DEBUG, "Buffer flag eos\n");
401 ret = AVERROR_EOF;
402 goto out;
403 }
404
405 p = OH_AVBuffer_GetAddr(output->buffer);
406 if (!p) {
407 av_log(avctx, AV_LOG_ERROR, "Failed to get output buffer addr\n");
408 ret = AVERROR_EXTERNAL;
409 goto out;
410 }
411 if (attr.flags & AVCODEC_BUFFER_FLAGS_CODEC_DATA) {
412 av_freep(&s->extradata);
413 s->extradata = av_malloc(attr.size + AV_INPUT_BUFFER_PADDING_SIZE);
414 if (!s->extradata) {
415 ret = AVERROR(ENOMEM);
416 goto out;
417 }
418 memset(s->extradata + attr.size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
419 memcpy(s->extradata, p + attr.offset, attr.size);
420 s->extradata_size = attr.size;
421 ret = 0;
422 goto out;
423 }
424
425 int64_t extradata_size = s->extradata_size;
426 s->extradata_size = 0;
427
428 if (extradata_size && (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) {
429 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
430 s->extradata, extradata_size);
431 if (ret < 0)
432 goto out;
433 s->extradata = NULL;
434 extradata_size = 0;
435 }
436
437 ret = ff_get_encode_buffer(avctx, pkt, attr.size + extradata_size, 0);
438 if (ret < 0)
439 goto out;
440
441 if (extradata_size)
442 memcpy(pkt->data, s->extradata, extradata_size);
443
444 memcpy(pkt->data + extradata_size, p + attr.offset, attr.size);
445 pkt->pts = av_rescale_q(attr.pts, AV_TIME_BASE_Q, avctx->time_base);
446 if (attr.flags & AVCODEC_BUFFER_FLAGS_SYNC_FRAME)
447 pkt->flags |= AV_PKT_FLAG_KEY;
448 ret = 0;
449out:
450 OH_VideoEncoder_FreeOutputBuffer(s->enc, output->index);
451 return ret;
452}
453
454static int oh_encode_send_hw_frame(AVCodecContext *avctx)
455{
456 OHCodecEncContext *s = avctx->priv_data;
457
458 if (s->eof_sent)
459 return 0;
460
461 if (s->frame->buf[0]) {
462 av_frame_unref(s->frame);
463 return 0;
464 }
465
466 OH_AVErrCode err = OH_VideoEncoder_NotifyEndOfStream(s->enc);
467 s->eof_sent = true;
468 return ff_oh_err_to_ff_err(err);
469}
470
471static int oh_encode_send_sw_frame(AVCodecContext *avctx, OHBufferQueueItem *input)
472{
473 OHCodecEncContext *s = avctx->priv_data;
474 AVFrame *frame = s->frame;
475 OH_AVErrCode err;
476 int ret;
477
478 if (!s->got_stream_info) {
479 // This shouldn't happen, add a warning message.
480 av_log(avctx, AV_LOG_WARNING,
481 "decoder didn't notify stream info, try get format explicitly\n");
482
483 OH_AVFormat *format = OH_VideoEncoder_GetOutputDescription(s->enc);
484 if (!format) {
485 av_log(avctx, AV_LOG_ERROR, "GetOutputDescription failed\n");
486 return AVERROR_EXTERNAL;
487 }
488
489 oh_encode_on_stream_changed(s->enc, format, avctx);
490 OH_AVFormat_Destroy(format);
491 if (!s->got_stream_info)
492 return AVERROR_EXTERNAL;
493 }
494
495 if (!frame->buf[0] && !s->eof_sent) {
496 OH_AVCodecBufferAttr attr = {
497 .flags = AVCODEC_BUFFER_FLAGS_EOS,
498 };
499 err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr);
500 if (err != AV_ERR_OK)
501 return ff_oh_err_to_ff_err(err);
502 err = OH_VideoEncoder_PushInputBuffer(s->enc, input->index);
503 if (err != AV_ERR_OK)
504 return ff_oh_err_to_ff_err(err);
505 s->eof_sent = true;
506 return 0;
507 }
508
509 uint8_t *p = OH_AVBuffer_GetAddr(input->buffer);
510 int32_t n = OH_AVBuffer_GetCapacity(input->buffer);
511 if (!p || n <= 0) {
512 av_log(avctx, AV_LOG_ERROR,
513 "Failed to get buffer addr (%p) or capacity (%d)\n",
514 p, n);
515 return AVERROR_EXTERNAL;
516 }
517
518 uint8_t *dst[4] = {0};
519 int dst_linesizes[4] = {0};
520 ret = av_image_fill_linesizes(dst_linesizes, frame->format, s->stride);
521 if (ret < 0)
522 return ret;
523 ret = av_image_fill_pointers(dst, frame->format, s->slice_height, p,
524 dst_linesizes);
525 if (ret < 0)
526 return ret;
527
528 av_image_copy2(dst, dst_linesizes, frame->data, frame->linesize,
529 frame->format, frame->width, frame->height);
530 OH_AVCodecBufferAttr attr = {
531 .size = n,
532 .offset = 0,
533 .pts = av_rescale_q(s->frame->pts, avctx->pkt_timebase,
534 AV_TIME_BASE_Q),
535 .flags = (s->frame->flags & AV_FRAME_FLAG_KEY)
536 ? AVCODEC_BUFFER_FLAGS_SYNC_FRAME : 0,
537 };
538
539 err = OH_AVBuffer_SetBufferAttr(input->buffer, &attr);
540 if (err != AV_ERR_OK) {
541 ret = ff_oh_err_to_ff_err(err);
542 return ret;
543 }
544 err = OH_VideoEncoder_PushInputBuffer(s->enc, input->index);
545 if (err != AV_ERR_OK) {
546 ret = ff_oh_err_to_ff_err(err);
547 av_log(avctx, AV_LOG_ERROR, "Push input buffer failed, %d, %s\n",
548 err, av_err2str(ret));
549 return ret;
550 }
551 av_frame_unref(s->frame);
552
553 return 0;
554}
555
556static int oh_encode_receive(AVCodecContext *avctx, AVPacket *pkt)
557{
558 OHCodecEncContext *s = avctx->priv_data;
559
560 while (1) {
561 OHBufferQueueItem buffer = {0};
562 int ret;
563
564 // Try get output
565 ff_mutex_lock(&s->output_mutex);
566 while (!s->encode_status) {
567 if (av_fifo_read(s->output_queue, &buffer, 1) >= 0)
568 break;
569 // Only wait after send EOF
570 if (s->eof_sent && !s->encode_status)
571 ff_cond_wait(&s->output_cond, &s->output_mutex);
572 else
573 break;
574 }
575
576 ret = s->encode_status;
577 ff_mutex_unlock(&s->output_mutex);
578
579 // Got a packet
580 if (buffer.buffer)
581 return oh_encode_output_packet(avctx, pkt, &buffer);
582 if (ret < 0)
583 return ret;
584
585 if (!s->frame->buf[0]) {
586 /* fetch new frame or eof */
587 ret = ff_encode_get_frame(avctx, s->frame);
588 if (ret < 0 && ret != AVERROR_EOF)
589 return ret;
590 }
591
592 if (s->native_window) {
593 ret = oh_encode_send_hw_frame(avctx);
594 if (ret < 0)
595 return ret;
596 continue;
597 }
598
599 // Wait input buffer
600 ff_mutex_lock(&s->input_mutex);
601 while (!s->encode_status) {
602 if (av_fifo_read(s->input_queue, &buffer, 1) >= 0)
603 break;
604 ff_cond_wait(&s->input_cond, &s->input_mutex);
605 }
606
607 ret = s->encode_status;
608 ff_mutex_unlock(&s->input_mutex);
609
610 if (ret < 0)
611 return ret;
612
613 ret = oh_encode_send_sw_frame(avctx, &buffer);
614 if (ret < 0)
615 return ret;
616 }
617
618 return AVERROR(EAGAIN);
619}
620
621static void oh_encode_flush(AVCodecContext *avctx)
622{
623 OHCodecEncContext *s = avctx->priv_data;
624
625 OH_VideoEncoder_Flush(s->enc);
626
627 ff_mutex_lock(&s->input_mutex);
628 ff_mutex_lock(&s->output_mutex);
629 av_fifo_reset2(s->input_queue);
630 av_fifo_reset2(s->output_queue);
631 s->encode_status = 0;
632 s->eof_sent = false;
633 ff_mutex_unlock(&s->output_mutex);
634 ff_mutex_unlock(&s->input_mutex);
635
636 OH_VideoEncoder_Start(s->enc);
637}
638
639static const AVCodecHWConfigInternal *const oh_hw_configs[] = {
640 &(const AVCodecHWConfigInternal) {
641 .public = {
642 .pix_fmt = AV_PIX_FMT_OHCODEC,
643 .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC,
644 },
645 .hwaccel = NULL,
646 },
647 NULL
648};
649
650static const FFCodecDefault ohcodec_defaults[] = {
651 {"g", "-2"},
652 {NULL},
653};
654
655#define OFFSET(x) offsetof(OHCodecEncContext, x)
656#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
657static const AVOption ohcodec_venc_options[] = {
658 {"codec_name", "Select codec by name",
659 OFFSET(name), AV_OPT_TYPE_STRING, .flags = VE},
660 {"allow_sw", "Allow software encoding",
661 OFFSET(allow_sw), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VE},
662 {"bitrate_mode", "Bitrate control method",
663 OFFSET(bitrate_mode), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE, .unit = "bitrate_mode"},
664 {"cbr", "Constant bitrate mode",
665 0, AV_OPT_TYPE_CONST, {.i64 = CBR}, 0, 0, VE, .unit = "bitrate_mode"},
666 {"vbr", "Variable bitrate mode",
667 0, AV_OPT_TYPE_CONST, {.i64 = VBR}, 0, 0, VE, .unit = "bitrate_mode"},
668 {"cq", "Constant quality mode",
669 0, AV_OPT_TYPE_CONST, {.i64 = CQ}, 0, 0, VE, .unit = "bitrate_mode"},
670 {NULL},
671};
672
673#define DECLARE_OHCODEC_CLASS(name) \
674static const AVClass name ## _oh_enc_class = { \
675 .class_name = #name "_ohcodec", \
676 .item_name = av_default_item_name, \
677 .option = ohcodec_venc_options, \
678 .version = LIBAVUTIL_VERSION_INT, \
679}; \
680
681#define DECLARE_OHCODEC_ENCODER(short_name, long_name, codec_id) \
682DECLARE_OHCODEC_CLASS(short_name) \
683const FFCodec ff_ ## short_name ## _oh_encoder = { \
684 .p.name = #short_name "_ohcodec", \
685 CODEC_LONG_NAME(long_name " OpenHarmony Codec"), \
686 .p.type = AVMEDIA_TYPE_VIDEO, \
687 .p.id = codec_id, \
688 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | \
689 AV_CODEC_CAP_HARDWARE | \
690 AV_CODEC_CAP_ENCODER_FLUSH, \
691 .priv_data_size = sizeof(OHCodecEncContext), \
692 CODEC_PIXFMTS_ARRAY(ohcodec_pix_fmts), \
693 .color_ranges = AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG, \
694 .defaults = ohcodec_defaults, \
695 .init = oh_encode_init, \
696 FF_CODEC_RECEIVE_PACKET_CB(oh_encode_receive), \
697 .close = oh_encode_close, \
698 .flush = oh_encode_flush, \
699 .p.priv_class = &short_name ## _oh_enc_class, \
700 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \
701 .p.wrapper_name = "ohcodec", \
702 .hw_configs = oh_hw_configs, \
703}; \
704
705#if CONFIG_H264_OH_ENCODER
706DECLARE_OHCODEC_ENCODER(h264, "H.264", AV_CODEC_ID_H264)
707#endif // CONFIG_H264_OH_ENCODER
708
709#if CONFIG_HEVC_OH_ENCODER
710DECLARE_OHCODEC_ENCODER(hevc, "H.265", AV_CODEC_ID_HEVC)
711#endif // CONFIG_HEVC_OH_ENCODER
712
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 732#define LIBAVCODEC_VERSION_MINOR 8
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