History

avcodec/ohenc: Add h264/hevc OpenHarmony encoders

Zhao Zhili committed 1 year ago

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

Showing the changes to libavcodec (6 of 8 files). Show all

Unified · Split

6 files
  1. libavcodec/Makefile +2 −0
  2. libavcodec/allcodecs.c +2 −0
  3. libavcodec/ohcodec.c +8 −0
  4. libavcodec/ohcodec.h +1 −0
  5. libavcodec/ohenc.c +712 −0
  6. libavcodec/version.h +1 −1
libavcodec/Makefile+2−0
@@ -429,6 +429,7 @@ OBJS-$(CONFIG_H264_MF_ENCODER) += mfenc.o mf_utils.o · 428 unmodified lines
429429 OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
430430 OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o
431431 OBJS-$(CONFIG_H264_OH_DECODER) += ohcodec.o ohdec.o
432+OBJS-$(CONFIG_H264_OH_ENCODER) += ohcodec.o ohenc.o
432433 OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o
433434 OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o
434435 OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o
@@ -458,6 +459,7 @@ OBJS-$(CONFIG_HEVC_MEDIACODEC_ENCODER) += mediacodecenc.o · 23 unmodified lines
458459 OBJS-$(CONFIG_HEVC_MF_ENCODER) += mfenc.o mf_utils.o
459460 OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o
460461 OBJS-$(CONFIG_HEVC_OH_DECODER) += ohcodec.o ohdec.o
462+OBJS-$(CONFIG_HEVC_OH_ENCODER) += ohcodec.o ohenc.o
461463 OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o
462464 OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc/ps_enc.o
463465 OBJS-$(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
861861 extern const FFCodec ff_h264_mf_encoder;
862862 extern const FFCodec ff_h264_nvenc_encoder;
863863 extern const FFCodec ff_h264_oh_decoder;
864+extern const FFCodec ff_h264_oh_encoder;
864865 extern const FFCodec ff_h264_omx_encoder;
865866 extern const FFCodec ff_h264_qsv_encoder;
866867 extern const FFCodec ff_h264_v4l2m2m_encoder;
@@ -876,6 +877,7 @@ extern const FFCodec ff_hevc_mediacodec_encoder; · 9 unmodified lines
876877 extern const FFCodec ff_hevc_mf_encoder;
877878 extern const FFCodec ff_hevc_nvenc_encoder;
878879 extern const FFCodec ff_hevc_oh_decoder;
880+extern const FFCodec ff_hevc_oh_encoder;
879881 extern const FFCodec ff_hevc_qsv_encoder;
880882 extern const FFCodec ff_hevc_v4l2m2m_encoder;
881883 extern 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
6969 return AV_PIX_FMT_NONE;
7070 }
7171
72+int 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
5252 }
5353
5454 enum AVPixelFormat ff_oh_pix_to_ff_pix(OH_AVPixelFormat oh_pix);
55+int ff_oh_pix_from_ff_pix(enum AVPixelFormat pix);
5556
5657 #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+
41+typedef 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+
70+static const enum AVPixelFormat ohcodec_pix_fmts[] = {
71+ AV_PIX_FMT_OHCODEC,
72+ AV_PIX_FMT_NV12,
73+ AV_PIX_FMT_NONE
74+};
75+
76+static 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+
113+static 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;
210+out:
211+ OH_AVFormat_Destroy(format);
212+ return ret;
213+}
214+
215+static 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+
232+static 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+
246+static 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+
265+static 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+
284+static 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+
320+static 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+
353+static 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+
386+static 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;
449+out:
450+ OH_VideoEncoder_FreeOutputBuffer(s->enc, output->index);
451+ return ret;
452+}
453+
454+static 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+
471+static 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+
556+static 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+
621+static 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+
639+static 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+
650+static 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
657+static 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) \
674+static 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) \
682+DECLARE_OHCODEC_CLASS(short_name) \
683+const 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
706+DECLARE_OHCODEC_ENCODER(h264, "H.264", AV_CODEC_ID_H264)
707+#endif // CONFIG_H264_OH_ENCODER
708+
709+#if CONFIG_HEVC_OH_ENCODER
710+DECLARE_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
2929
3030 #include "version_major.h"
3131
32−#define LIBAVCODEC_VERSION_MINOR 7
32+#define LIBAVCODEC_VERSION_MINOR 8
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