xref: /OK3568_Linux_fs/external/gstreamer-rockchip/gst/rockchipmpp/gstmppenc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2017 Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun  *     Author: Randy Li <randy.li@rock-chips.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2021 Rockchip Electronics Co., Ltd
6*4882a593Smuzhiyun  *     Author: Jeffy Chen <jeffy.chen@rock-chips.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * This library is free software; you can redistribute it and/or
9*4882a593Smuzhiyun  * modify it under the terms of the GNU Library General Public
10*4882a593Smuzhiyun  * License as published by the Free Software Foundation; either
11*4882a593Smuzhiyun  * version 2 of the License, or (at your option) any later version.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * This library is distributed in the hope that it will be useful,
14*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16*4882a593Smuzhiyun  * Library General Public License for more details.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * You should have received a copy of the GNU Library General Public
19*4882a593Smuzhiyun  * License along with this library; if not, write to the
20*4882a593Smuzhiyun  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21*4882a593Smuzhiyun  * Boston, MA 02110-1301, USA.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #ifdef HAVE_CONFIG_H
26*4882a593Smuzhiyun #include "config.h"
27*4882a593Smuzhiyun #endif
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include <string.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include "gstmppallocator.h"
32*4882a593Smuzhiyun #include "gstmppenc.h"
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define GST_CAT_DEFAULT mpp_enc_debug
35*4882a593Smuzhiyun GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #define parent_class gst_mpp_enc_parent_class
38*4882a593Smuzhiyun G_DEFINE_ABSTRACT_TYPE (GstMppEnc, gst_mpp_enc, GST_TYPE_VIDEO_ENCODER);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define MPP_PENDING_MAX 2       /* Max number of MPP pending frame */
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define GST_MPP_ENC_TASK_STARTED(encoder) \
43*4882a593Smuzhiyun     (gst_pad_get_task_state ((encoder)->srcpad) == GST_TASK_STARTED)
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define GST_MPP_ENC_MUTEX(encoder) (&GST_MPP_ENC (encoder)->mutex)
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define GST_MPP_ENC_LOCK(encoder) \
48*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder); \
49*4882a593Smuzhiyun   g_mutex_lock (GST_MPP_ENC_MUTEX (encoder)); \
50*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define GST_MPP_ENC_UNLOCK(encoder) \
53*4882a593Smuzhiyun   g_mutex_unlock (GST_MPP_ENC_MUTEX (encoder));
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define GST_MPP_ENC_EVENT_MUTEX(encoder) (&GST_MPP_ENC (encoder)->event_mutex)
56*4882a593Smuzhiyun #define GST_MPP_ENC_EVENT_COND(encoder) (&GST_MPP_ENC (encoder)->event_cond)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define GST_MPP_ENC_BROADCAST(encoder) \
59*4882a593Smuzhiyun   g_mutex_lock (GST_MPP_ENC_EVENT_MUTEX (encoder)); \
60*4882a593Smuzhiyun   g_cond_broadcast (GST_MPP_ENC_EVENT_COND (encoder)); \
61*4882a593Smuzhiyun   g_mutex_unlock (GST_MPP_ENC_EVENT_MUTEX (encoder));
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define GST_MPP_ENC_WAIT(encoder, condition) \
64*4882a593Smuzhiyun   g_mutex_lock (GST_MPP_ENC_EVENT_MUTEX (encoder)); \
65*4882a593Smuzhiyun   while (!(condition)) \
66*4882a593Smuzhiyun     g_cond_wait (GST_MPP_ENC_EVENT_COND (encoder), \
67*4882a593Smuzhiyun         GST_MPP_ENC_EVENT_MUTEX (encoder)); \
68*4882a593Smuzhiyun   g_mutex_unlock (GST_MPP_ENC_EVENT_MUTEX (encoder));
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define DEFAULT_PROP_HEADER_MODE MPP_ENC_HEADER_MODE_DEFAULT    /* First frame */
71*4882a593Smuzhiyun #define DEFAULT_PROP_SEI_MODE MPP_ENC_SEI_MODE_DISABLE
72*4882a593Smuzhiyun #define DEFAULT_PROP_RC_MODE MPP_ENC_RC_MODE_CBR
73*4882a593Smuzhiyun #define DEFAULT_PROP_ROTATION 0
74*4882a593Smuzhiyun #define DEFAULT_PROP_GOP -1     /* Same as FPS */
75*4882a593Smuzhiyun #define DEFAULT_PROP_MAX_REENC 1
76*4882a593Smuzhiyun #define DEFAULT_PROP_BPS 0      /* Auto */
77*4882a593Smuzhiyun #define DEFAULT_PROP_BPS_MIN 0  /* Auto */
78*4882a593Smuzhiyun #define DEFAULT_PROP_BPS_MAX 0  /* Auto */
79*4882a593Smuzhiyun #define DEFAULT_PROP_WIDTH 0    /* Original */
80*4882a593Smuzhiyun #define DEFAULT_PROP_HEIGHT 0   /* Original */
81*4882a593Smuzhiyun #define DEFAULT_PROP_ZERO_COPY_PKT TRUE
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun /* Input isn't ARM AFBC by default */
84*4882a593Smuzhiyun static GstVideoFormat DEFAULT_PROP_ARM_AFBC = FALSE;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun #define DEFAULT_FPS 30
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun enum
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun   PROP_0,
91*4882a593Smuzhiyun   PROP_HEADER_MODE,
92*4882a593Smuzhiyun   PROP_RC_MODE,
93*4882a593Smuzhiyun   PROP_ROTATION,
94*4882a593Smuzhiyun   PROP_SEI_MODE,
95*4882a593Smuzhiyun   PROP_GOP,
96*4882a593Smuzhiyun   PROP_MAX_REENC,
97*4882a593Smuzhiyun   PROP_BPS,
98*4882a593Smuzhiyun   PROP_BPS_MIN,
99*4882a593Smuzhiyun   PROP_BPS_MAX,
100*4882a593Smuzhiyun   PROP_WIDTH,
101*4882a593Smuzhiyun   PROP_HEIGHT,
102*4882a593Smuzhiyun   PROP_ZERO_COPY_PKT,
103*4882a593Smuzhiyun   PROP_ARM_AFBC,
104*4882a593Smuzhiyun   PROP_LAST,
105*4882a593Smuzhiyun };
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun static const MppFrameFormat gst_mpp_enc_formats[] = {
108*4882a593Smuzhiyun   MPP_FMT_YUV420SP,
109*4882a593Smuzhiyun   MPP_FMT_YUV420P,
110*4882a593Smuzhiyun   MPP_FMT_YUV422_YUYV,
111*4882a593Smuzhiyun   MPP_FMT_YUV422_UYVY,
112*4882a593Smuzhiyun   MPP_FMT_YUV444SP,
113*4882a593Smuzhiyun   MPP_FMT_YUV444P,
114*4882a593Smuzhiyun   MPP_FMT_RGB565LE,
115*4882a593Smuzhiyun   MPP_FMT_BGR565LE,
116*4882a593Smuzhiyun   MPP_FMT_ARGB8888,
117*4882a593Smuzhiyun   MPP_FMT_ABGR8888,
118*4882a593Smuzhiyun   MPP_FMT_RGBA8888,
119*4882a593Smuzhiyun   MPP_FMT_BGRA8888,
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun static gboolean
gst_mpp_enc_format_supported(MppFrameFormat format)123*4882a593Smuzhiyun gst_mpp_enc_format_supported (MppFrameFormat format)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun   guint i;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun   for (i = 0; i < ARRAY_SIZE (gst_mpp_enc_formats); i++) {
128*4882a593Smuzhiyun     if (format == gst_mpp_enc_formats[i])
129*4882a593Smuzhiyun       return TRUE;
130*4882a593Smuzhiyun   }
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun   return FALSE;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun gboolean
gst_mpp_enc_supported(MppCodingType mpp_type)136*4882a593Smuzhiyun gst_mpp_enc_supported (MppCodingType mpp_type)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun   MppCtx mpp_ctx;
139*4882a593Smuzhiyun   MppApi *mpi;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun   if (mpp_create (&mpp_ctx, &mpi))
142*4882a593Smuzhiyun     return FALSE;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun   if (mpp_init (mpp_ctx, MPP_CTX_ENC, mpp_type)) {
145*4882a593Smuzhiyun     mpp_destroy (mpp_ctx);
146*4882a593Smuzhiyun     return FALSE;
147*4882a593Smuzhiyun   }
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun   mpp_destroy (mpp_ctx);
150*4882a593Smuzhiyun   return TRUE;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun static gboolean
gst_mpp_enc_video_info_matched(GstVideoInfo * info,GstVideoInfo * other)154*4882a593Smuzhiyun gst_mpp_enc_video_info_matched (GstVideoInfo * info, GstVideoInfo * other)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun   guint i;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun   if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_INFO_FORMAT (other))
159*4882a593Smuzhiyun     return FALSE;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun   if (GST_VIDEO_INFO_SIZE (info) != GST_VIDEO_INFO_SIZE (other))
162*4882a593Smuzhiyun     return FALSE;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun   if (GST_VIDEO_INFO_WIDTH (info) != GST_VIDEO_INFO_WIDTH (other))
165*4882a593Smuzhiyun     return FALSE;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun   if (GST_VIDEO_INFO_HEIGHT (info) != GST_VIDEO_INFO_HEIGHT (other))
168*4882a593Smuzhiyun     return FALSE;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun   for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
171*4882a593Smuzhiyun     if (GST_VIDEO_INFO_PLANE_STRIDE (info,
172*4882a593Smuzhiyun             i) != GST_VIDEO_INFO_PLANE_STRIDE (other, i))
173*4882a593Smuzhiyun       return FALSE;
174*4882a593Smuzhiyun     if (GST_VIDEO_INFO_PLANE_OFFSET (info,
175*4882a593Smuzhiyun             i) != GST_VIDEO_INFO_PLANE_OFFSET (other, i))
176*4882a593Smuzhiyun       return FALSE;
177*4882a593Smuzhiyun   }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun   return TRUE;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun gboolean
gst_mpp_enc_video_info_align(GstVideoInfo * info)183*4882a593Smuzhiyun gst_mpp_enc_video_info_align (GstVideoInfo * info)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun   gint vstride = 0;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun   /* Allow skipping vstride aligning for RKVENC */
188*4882a593Smuzhiyun   if (g_getenv ("GST_MPP_ENC_UNALIGNED_VSTRIDE"))
189*4882a593Smuzhiyun     vstride = GST_MPP_VIDEO_INFO_VSTRIDE (info);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun   return gst_mpp_video_info_align (info, 0, vstride);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun static void
gst_mpp_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)195*4882a593Smuzhiyun gst_mpp_enc_set_property (GObject * object,
196*4882a593Smuzhiyun     guint prop_id, const GValue * value, GParamSpec * pspec)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
199*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun   switch (prop_id) {
202*4882a593Smuzhiyun     case PROP_HEADER_MODE:{
203*4882a593Smuzhiyun       MppEncHeaderMode header_mode = g_value_get_enum (value);
204*4882a593Smuzhiyun       if (self->header_mode == header_mode)
205*4882a593Smuzhiyun         return;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun       self->header_mode = header_mode;
208*4882a593Smuzhiyun       break;
209*4882a593Smuzhiyun     }
210*4882a593Smuzhiyun     case PROP_SEI_MODE:{
211*4882a593Smuzhiyun       MppEncSeiMode sei_mode = g_value_get_enum (value);
212*4882a593Smuzhiyun       if (self->sei_mode == sei_mode)
213*4882a593Smuzhiyun         return;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun       self->sei_mode = sei_mode;
216*4882a593Smuzhiyun       break;
217*4882a593Smuzhiyun     }
218*4882a593Smuzhiyun     case PROP_RC_MODE:{
219*4882a593Smuzhiyun       MppEncRcMode rc_mode = g_value_get_enum (value);
220*4882a593Smuzhiyun       if (self->rc_mode == rc_mode)
221*4882a593Smuzhiyun         return;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun       self->rc_mode = rc_mode;
224*4882a593Smuzhiyun       break;
225*4882a593Smuzhiyun     }
226*4882a593Smuzhiyun     case PROP_GOP:{
227*4882a593Smuzhiyun       gint gop = g_value_get_int (value);
228*4882a593Smuzhiyun       if (self->gop == gop)
229*4882a593Smuzhiyun         return;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun       self->gop = gop;
232*4882a593Smuzhiyun       break;
233*4882a593Smuzhiyun     }
234*4882a593Smuzhiyun     case PROP_MAX_REENC:{
235*4882a593Smuzhiyun       guint max_reenc = g_value_get_uint (value);
236*4882a593Smuzhiyun       if (self->max_reenc == max_reenc)
237*4882a593Smuzhiyun         return;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun       self->max_reenc = max_reenc;
240*4882a593Smuzhiyun       break;
241*4882a593Smuzhiyun     }
242*4882a593Smuzhiyun     case PROP_BPS:{
243*4882a593Smuzhiyun       guint bps = g_value_get_uint (value);
244*4882a593Smuzhiyun       if (self->bps == bps)
245*4882a593Smuzhiyun         return;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun       self->bps = bps;
248*4882a593Smuzhiyun       break;
249*4882a593Smuzhiyun     }
250*4882a593Smuzhiyun     case PROP_BPS_MIN:{
251*4882a593Smuzhiyun       guint bps_min = g_value_get_uint (value);
252*4882a593Smuzhiyun       if (self->bps_min == bps_min)
253*4882a593Smuzhiyun         return;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun       self->bps_min = bps_min;
256*4882a593Smuzhiyun       break;
257*4882a593Smuzhiyun     }
258*4882a593Smuzhiyun     case PROP_BPS_MAX:{
259*4882a593Smuzhiyun       guint bps_max = g_value_get_uint (value);
260*4882a593Smuzhiyun       if (self->bps_max == bps_max)
261*4882a593Smuzhiyun         return;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun       self->bps_max = bps_max;
264*4882a593Smuzhiyun       break;
265*4882a593Smuzhiyun     }
266*4882a593Smuzhiyun     case PROP_ROTATION:{
267*4882a593Smuzhiyun       if (self->input_state)
268*4882a593Smuzhiyun         GST_WARNING_OBJECT (encoder, "unable to change rotation");
269*4882a593Smuzhiyun       else
270*4882a593Smuzhiyun         self->rotation = g_value_get_enum (value);
271*4882a593Smuzhiyun       return;
272*4882a593Smuzhiyun     }
273*4882a593Smuzhiyun     case PROP_WIDTH:{
274*4882a593Smuzhiyun       if (self->input_state)
275*4882a593Smuzhiyun         GST_WARNING_OBJECT (encoder, "unable to change width");
276*4882a593Smuzhiyun       else
277*4882a593Smuzhiyun         self->width = g_value_get_uint (value);
278*4882a593Smuzhiyun       return;
279*4882a593Smuzhiyun     }
280*4882a593Smuzhiyun     case PROP_HEIGHT:{
281*4882a593Smuzhiyun       if (self->input_state)
282*4882a593Smuzhiyun         GST_WARNING_OBJECT (encoder, "unable to change height");
283*4882a593Smuzhiyun       else
284*4882a593Smuzhiyun         self->height = g_value_get_uint (value);
285*4882a593Smuzhiyun       return;
286*4882a593Smuzhiyun     }
287*4882a593Smuzhiyun     case PROP_ZERO_COPY_PKT:{
288*4882a593Smuzhiyun       self->zero_copy_pkt = g_value_get_boolean (value);
289*4882a593Smuzhiyun       return;
290*4882a593Smuzhiyun     }
291*4882a593Smuzhiyun     case PROP_ARM_AFBC:{
292*4882a593Smuzhiyun       if (self->input_state)
293*4882a593Smuzhiyun         GST_WARNING_OBJECT (encoder, "unable to change ARM AFBC");
294*4882a593Smuzhiyun       else
295*4882a593Smuzhiyun         self->arm_afbc = g_value_get_boolean (value);
296*4882a593Smuzhiyun       return;
297*4882a593Smuzhiyun     }
298*4882a593Smuzhiyun     default:
299*4882a593Smuzhiyun       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
300*4882a593Smuzhiyun       return;
301*4882a593Smuzhiyun   }
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun   self->prop_dirty = TRUE;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun static void
gst_mpp_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)307*4882a593Smuzhiyun gst_mpp_enc_get_property (GObject * object,
308*4882a593Smuzhiyun     guint prop_id, GValue * value, GParamSpec * pspec)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (object);
311*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun   switch (prop_id) {
314*4882a593Smuzhiyun     case PROP_HEADER_MODE:
315*4882a593Smuzhiyun       g_value_set_enum (value, self->header_mode);
316*4882a593Smuzhiyun       break;
317*4882a593Smuzhiyun     case PROP_SEI_MODE:
318*4882a593Smuzhiyun       g_value_set_enum (value, self->sei_mode);
319*4882a593Smuzhiyun       break;
320*4882a593Smuzhiyun     case PROP_RC_MODE:
321*4882a593Smuzhiyun       g_value_set_enum (value, self->rc_mode);
322*4882a593Smuzhiyun       break;
323*4882a593Smuzhiyun     case PROP_ROTATION:
324*4882a593Smuzhiyun       g_value_set_enum (value, self->rotation);
325*4882a593Smuzhiyun       break;
326*4882a593Smuzhiyun     case PROP_GOP:
327*4882a593Smuzhiyun       g_value_set_int (value, self->gop);
328*4882a593Smuzhiyun       break;
329*4882a593Smuzhiyun     case PROP_MAX_REENC:
330*4882a593Smuzhiyun       g_value_set_uint (value, self->max_reenc);
331*4882a593Smuzhiyun       break;
332*4882a593Smuzhiyun     case PROP_BPS:
333*4882a593Smuzhiyun       g_value_set_uint (value, self->bps);
334*4882a593Smuzhiyun       break;
335*4882a593Smuzhiyun     case PROP_BPS_MIN:
336*4882a593Smuzhiyun       g_value_set_uint (value, self->bps_min);
337*4882a593Smuzhiyun       break;
338*4882a593Smuzhiyun     case PROP_BPS_MAX:
339*4882a593Smuzhiyun       g_value_set_uint (value, self->bps_max);
340*4882a593Smuzhiyun       break;
341*4882a593Smuzhiyun     case PROP_WIDTH:
342*4882a593Smuzhiyun       g_value_set_uint (value, self->width);
343*4882a593Smuzhiyun       break;
344*4882a593Smuzhiyun     case PROP_HEIGHT:
345*4882a593Smuzhiyun       g_value_set_uint (value, self->height);
346*4882a593Smuzhiyun       break;
347*4882a593Smuzhiyun     case PROP_ZERO_COPY_PKT:
348*4882a593Smuzhiyun       g_value_set_boolean (value, self->zero_copy_pkt);
349*4882a593Smuzhiyun       break;
350*4882a593Smuzhiyun     case PROP_ARM_AFBC:
351*4882a593Smuzhiyun       g_value_set_boolean (value, self->arm_afbc);
352*4882a593Smuzhiyun       break;
353*4882a593Smuzhiyun     default:
354*4882a593Smuzhiyun       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
355*4882a593Smuzhiyun       return;
356*4882a593Smuzhiyun   }
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun gboolean
gst_mpp_enc_apply_properties(GstVideoEncoder * encoder)360*4882a593Smuzhiyun gst_mpp_enc_apply_properties (GstVideoEncoder * encoder)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
363*4882a593Smuzhiyun   GstVideoInfo *info = &self->info;
364*4882a593Smuzhiyun   gint fps_num = GST_VIDEO_INFO_FPS_N (info);
365*4882a593Smuzhiyun   gint fps_denorm = GST_VIDEO_INFO_FPS_D (info);
366*4882a593Smuzhiyun   gint fps = fps_num / fps_denorm;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun   if (!self->prop_dirty)
369*4882a593Smuzhiyun     return TRUE;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun   self->prop_dirty = FALSE;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun   if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_SEI_CFG, &self->sei_mode))
374*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "failed to set sei mode");
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun   if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_HEADER_MODE,
377*4882a593Smuzhiyun           &self->header_mode))
378*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "failed to set header mode");
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:gop",
381*4882a593Smuzhiyun       self->gop < 0 ? fps : self->gop);
382*4882a593Smuzhiyun   mpp_enc_cfg_set_u32 (self->mpp_cfg, "rc:max_reenc_times", self->max_reenc);
383*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:mode", self->rc_mode);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun   if (!self->bps)
386*4882a593Smuzhiyun     self->bps =
387*4882a593Smuzhiyun         GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info) / 8 * fps;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun   if (!self->bps || self->rc_mode == MPP_ENC_RC_MODE_FIXQP) {
390*4882a593Smuzhiyun     /* BPS settings are ignored */
391*4882a593Smuzhiyun   } else if (self->rc_mode == MPP_ENC_RC_MODE_CBR) {
392*4882a593Smuzhiyun     /* CBR mode has narrow bound */
393*4882a593Smuzhiyun     mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_target", self->bps);
394*4882a593Smuzhiyun     mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_max",
395*4882a593Smuzhiyun         self->bps_max ? : self->bps * 17 / 16);
396*4882a593Smuzhiyun     mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_min",
397*4882a593Smuzhiyun         self->bps_min ? : self->bps * 15 / 16);
398*4882a593Smuzhiyun   } else if (self->rc_mode == MPP_ENC_RC_MODE_VBR) {
399*4882a593Smuzhiyun     /* VBR mode has wide bound */
400*4882a593Smuzhiyun     mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_target", self->bps);
401*4882a593Smuzhiyun     mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_max",
402*4882a593Smuzhiyun         self->bps_max ? : self->bps * 17 / 16);
403*4882a593Smuzhiyun     mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:bps_min",
404*4882a593Smuzhiyun         self->bps_min ? : self->bps * 1 / 16);
405*4882a593Smuzhiyun   }
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun   if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_CFG, self->mpp_cfg)) {
408*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "failed to set enc cfg");
409*4882a593Smuzhiyun     return FALSE;
410*4882a593Smuzhiyun   }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun   return TRUE;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun gboolean
gst_mpp_enc_set_src_caps(GstVideoEncoder * encoder,GstCaps * caps)416*4882a593Smuzhiyun gst_mpp_enc_set_src_caps (GstVideoEncoder * encoder, GstCaps * caps)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
419*4882a593Smuzhiyun   GstVideoInfo *info = &self->info;
420*4882a593Smuzhiyun   GstVideoCodecState *output_state;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun   gst_caps_set_simple (caps,
423*4882a593Smuzhiyun       "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH (info),
424*4882a593Smuzhiyun       "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT (info), NULL);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "output caps: %" GST_PTR_FORMAT, caps);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun   output_state = gst_video_encoder_set_output_state (encoder,
429*4882a593Smuzhiyun       caps, self->input_state);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun   GST_VIDEO_INFO_WIDTH (&output_state->info) = GST_VIDEO_INFO_WIDTH (info);
432*4882a593Smuzhiyun   GST_VIDEO_INFO_HEIGHT (&output_state->info) = GST_VIDEO_INFO_HEIGHT (info);
433*4882a593Smuzhiyun   gst_video_codec_state_unref (output_state);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun   return gst_video_encoder_negotiate (encoder);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun static void
gst_mpp_enc_stop_task(GstVideoEncoder * encoder,gboolean drain)439*4882a593Smuzhiyun gst_mpp_enc_stop_task (GstVideoEncoder * encoder, gboolean drain)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
442*4882a593Smuzhiyun   GstTask *task = encoder->srcpad->task;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun   if (!GST_MPP_ENC_TASK_STARTED (encoder))
445*4882a593Smuzhiyun     return;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "stopping encoding thread");
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun   /* Discard pending frames */
450*4882a593Smuzhiyun   if (!drain)
451*4882a593Smuzhiyun     self->pending_frames = 0;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun   GST_MPP_ENC_BROADCAST (encoder);
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
456*4882a593Smuzhiyun   /* Wait for task thread to pause */
457*4882a593Smuzhiyun   if (task) {
458*4882a593Smuzhiyun     GST_OBJECT_LOCK (task);
459*4882a593Smuzhiyun     while (GST_TASK_STATE (task) == GST_TASK_STARTED)
460*4882a593Smuzhiyun       GST_TASK_WAIT (task);
461*4882a593Smuzhiyun     GST_OBJECT_UNLOCK (task);
462*4882a593Smuzhiyun   }
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun   gst_pad_stop_task (encoder->srcpad);
465*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun static void
gst_mpp_enc_reset(GstVideoEncoder * encoder,gboolean drain,gboolean final)469*4882a593Smuzhiyun gst_mpp_enc_reset (GstVideoEncoder * encoder, gboolean drain, gboolean final)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun   GST_MPP_ENC_LOCK (encoder);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "resetting");
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun   self->flushing = TRUE;
478*4882a593Smuzhiyun   self->draining = drain;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun   gst_mpp_enc_stop_task (encoder, drain);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun   self->flushing = final;
483*4882a593Smuzhiyun   self->draining = FALSE;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun   self->mpi->reset (self->mpp_ctx);
486*4882a593Smuzhiyun   self->task_ret = GST_FLOW_OK;
487*4882a593Smuzhiyun   self->pending_frames = 0;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun   /* Force re-apply prop */
490*4882a593Smuzhiyun   self->prop_dirty = TRUE;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun   GST_MPP_ENC_UNLOCK (encoder);
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun static gboolean
gst_mpp_enc_start(GstVideoEncoder * encoder)496*4882a593Smuzhiyun gst_mpp_enc_start (GstVideoEncoder * encoder)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "starting");
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun   gst_video_info_init (&self->info);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun   self->allocator = gst_mpp_allocator_new ();
505*4882a593Smuzhiyun   if (!self->allocator)
506*4882a593Smuzhiyun     return FALSE;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun   gst_mpp_allocator_set_cacheable (self->allocator, FALSE);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun   if (mpp_create (&self->mpp_ctx, &self->mpi))
511*4882a593Smuzhiyun     goto err_unref_alloc;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun   if (mpp_init (self->mpp_ctx, MPP_CTX_ENC, self->mpp_type))
514*4882a593Smuzhiyun     goto err_destroy_mpp;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun   if (mpp_frame_init (&self->mpp_frame))
517*4882a593Smuzhiyun     goto err_destroy_mpp;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun   if (mpp_enc_cfg_init (&self->mpp_cfg))
520*4882a593Smuzhiyun     goto err_deinit_frame;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun   if (self->mpi->control (self->mpp_ctx, MPP_ENC_GET_CFG, self->mpp_cfg))
523*4882a593Smuzhiyun     goto err_deinit_cfg;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun   self->task_ret = GST_FLOW_OK;
526*4882a593Smuzhiyun   self->input_state = NULL;
527*4882a593Smuzhiyun   self->flushing = FALSE;
528*4882a593Smuzhiyun   self->pending_frames = 0;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun   g_mutex_init (&self->mutex);
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun   g_mutex_init (&self->event_mutex);
533*4882a593Smuzhiyun   g_cond_init (&self->event_cond);
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "started");
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun   return TRUE;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun err_deinit_cfg:
540*4882a593Smuzhiyun   mpp_enc_cfg_deinit (self->mpp_cfg);
541*4882a593Smuzhiyun err_deinit_frame:
542*4882a593Smuzhiyun   mpp_frame_deinit (&self->mpp_frame);
543*4882a593Smuzhiyun err_destroy_mpp:
544*4882a593Smuzhiyun   mpp_destroy (self->mpp_ctx);
545*4882a593Smuzhiyun err_unref_alloc:
546*4882a593Smuzhiyun   gst_object_unref (self->allocator);
547*4882a593Smuzhiyun   return FALSE;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun static gboolean
gst_mpp_enc_stop(GstVideoEncoder * encoder)551*4882a593Smuzhiyun gst_mpp_enc_stop (GstVideoEncoder * encoder)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "stopping");
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
558*4882a593Smuzhiyun   gst_mpp_enc_reset (encoder, FALSE, TRUE);
559*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun   g_cond_clear (&self->event_cond);
562*4882a593Smuzhiyun   g_mutex_clear (&self->event_mutex);
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun   g_mutex_clear (&self->mutex);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun   mpp_enc_cfg_deinit (self->mpp_cfg);
567*4882a593Smuzhiyun   mpp_frame_set_buffer (self->mpp_frame, NULL);
568*4882a593Smuzhiyun   mpp_frame_deinit (&self->mpp_frame);
569*4882a593Smuzhiyun   mpp_destroy (self->mpp_ctx);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun   gst_object_unref (self->allocator);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun   if (self->input_state)
574*4882a593Smuzhiyun     gst_video_codec_state_unref (self->input_state);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "stopped");
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun   return TRUE;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun static gboolean
gst_mpp_enc_flush(GstVideoEncoder * encoder)582*4882a593Smuzhiyun gst_mpp_enc_flush (GstVideoEncoder * encoder)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun   GST_DEBUG_OBJECT (encoder, "flushing");
585*4882a593Smuzhiyun   gst_mpp_enc_reset (encoder, FALSE, FALSE);
586*4882a593Smuzhiyun   return TRUE;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun static gboolean
gst_mpp_enc_finish(GstVideoEncoder * encoder)590*4882a593Smuzhiyun gst_mpp_enc_finish (GstVideoEncoder * encoder)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun   GST_DEBUG_OBJECT (encoder, "finishing");
593*4882a593Smuzhiyun   gst_mpp_enc_reset (encoder, TRUE, FALSE);
594*4882a593Smuzhiyun   return GST_FLOW_OK;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun static gboolean
gst_mpp_enc_set_format(GstVideoEncoder * encoder,GstVideoCodecState * state)598*4882a593Smuzhiyun gst_mpp_enc_set_format (GstVideoEncoder * encoder, GstVideoCodecState * state)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
601*4882a593Smuzhiyun   GstVideoInfo *info = &self->info;
602*4882a593Smuzhiyun   MppFrameFormat format;
603*4882a593Smuzhiyun   gint width, height, hstride, vstride;
604*4882a593Smuzhiyun   gboolean convert = FALSE;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "setting format: %" GST_PTR_FORMAT, state->caps);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun   if (self->input_state) {
609*4882a593Smuzhiyun     if (gst_caps_is_strictly_equal (self->input_state->caps, state->caps))
610*4882a593Smuzhiyun       return TRUE;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun     gst_mpp_enc_reset (encoder, TRUE, FALSE);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun     gst_video_codec_state_unref (self->input_state);
615*4882a593Smuzhiyun     self->input_state = NULL;
616*4882a593Smuzhiyun   }
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun   self->input_state = gst_video_codec_state_ref (state);
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun   *info = state->info;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun   if (!gst_mpp_enc_video_info_align (info))
623*4882a593Smuzhiyun     return FALSE;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun   format = gst_mpp_gst_format_to_mpp_format (GST_VIDEO_INFO_FORMAT (info));
626*4882a593Smuzhiyun   width = GST_VIDEO_INFO_WIDTH (info);
627*4882a593Smuzhiyun   height = GST_VIDEO_INFO_HEIGHT (info);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun   if (self->rotation % 180)
630*4882a593Smuzhiyun     SWAP (width, height);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun   width = self->width ? : width;
633*4882a593Smuzhiyun   height = self->height ? : height;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun   /* Check for conversion */
636*4882a593Smuzhiyun   if (self->rotation || !gst_mpp_enc_format_supported (format) ||
637*4882a593Smuzhiyun       width != GST_VIDEO_INFO_WIDTH (info) ||
638*4882a593Smuzhiyun       height != GST_VIDEO_INFO_HEIGHT (info)) {
639*4882a593Smuzhiyun     if (!gst_mpp_use_rga ()) {
640*4882a593Smuzhiyun       GST_ERROR_OBJECT (self, "unable to convert without RGA");
641*4882a593Smuzhiyun       return FALSE;
642*4882a593Smuzhiyun     }
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun     convert = TRUE;
645*4882a593Smuzhiyun   }
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun   /* Check for alignment */
648*4882a593Smuzhiyun   if (!gst_mpp_enc_video_info_matched (info, &state->info))
649*4882a593Smuzhiyun     convert = TRUE;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun   if (convert) {
652*4882a593Smuzhiyun     /* Prefer NV12 when using RGA conversion */
653*4882a593Smuzhiyun     if (gst_mpp_use_rga ())
654*4882a593Smuzhiyun       format = MPP_FMT_YUV420SP;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun     gst_mpp_video_info_update_format (info,
657*4882a593Smuzhiyun         gst_mpp_mpp_format_to_gst_format (format), width, height);
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun     if (!gst_mpp_enc_video_info_align (info))
660*4882a593Smuzhiyun       return FALSE;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun     GST_INFO_OBJECT (self, "converting to aligned %s",
663*4882a593Smuzhiyun         gst_mpp_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
664*4882a593Smuzhiyun   }
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun   hstride = GST_MPP_VIDEO_INFO_HSTRIDE (info);
667*4882a593Smuzhiyun   vstride = GST_MPP_VIDEO_INFO_VSTRIDE (info);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun   GST_INFO_OBJECT (self, "applying %s%s %dx%d (%dx%d)",
670*4882a593Smuzhiyun       gst_mpp_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)),
671*4882a593Smuzhiyun       self->arm_afbc ? "(AFBC)" : "", width, height, hstride, vstride);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun   if (self->arm_afbc) {
674*4882a593Smuzhiyun     if (self->mpp_type != MPP_VIDEO_CodingAVC &&
675*4882a593Smuzhiyun         self->mpp_type != MPP_VIDEO_CodingHEVC) {
676*4882a593Smuzhiyun       GST_WARNING_OBJECT (self, "Only H.264 and H.265 support ARM AFBC");
677*4882a593Smuzhiyun       self->arm_afbc = FALSE;
678*4882a593Smuzhiyun     } else {
679*4882a593Smuzhiyun       format |= MPP_FRAME_FBC_AFBC_V2;
680*4882a593Smuzhiyun     }
681*4882a593Smuzhiyun   }
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun   mpp_frame_set_fmt (self->mpp_frame, format);
684*4882a593Smuzhiyun   mpp_frame_set_width (self->mpp_frame, width);
685*4882a593Smuzhiyun   mpp_frame_set_height (self->mpp_frame, height);
686*4882a593Smuzhiyun   mpp_frame_set_hor_stride (self->mpp_frame, hstride);
687*4882a593Smuzhiyun   mpp_frame_set_ver_stride (self->mpp_frame, vstride);
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun   if (!GST_VIDEO_INFO_FPS_N (info) || GST_VIDEO_INFO_FPS_N (info) > 240) {
690*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "framerate (%d/%d) is insane!",
691*4882a593Smuzhiyun         GST_VIDEO_INFO_FPS_N (info), GST_VIDEO_INFO_FPS_D (info));
692*4882a593Smuzhiyun     GST_VIDEO_INFO_FPS_N (info) = DEFAULT_FPS;
693*4882a593Smuzhiyun   }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:format", format);
696*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:width", width);
697*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:height", height);
698*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:hor_stride",
699*4882a593Smuzhiyun       GST_MPP_VIDEO_INFO_HSTRIDE (info));
700*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "prep:ver_stride",
701*4882a593Smuzhiyun       GST_MPP_VIDEO_INFO_VSTRIDE (info));
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_in_flex", 0);
704*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_in_num",
705*4882a593Smuzhiyun       GST_VIDEO_INFO_FPS_N (info));
706*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_in_denorm",
707*4882a593Smuzhiyun       GST_VIDEO_INFO_FPS_D (info));
708*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_out_flex", 0);
709*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_out_num",
710*4882a593Smuzhiyun       GST_VIDEO_INFO_FPS_N (info));
711*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:fps_out_denorm",
712*4882a593Smuzhiyun       GST_VIDEO_INFO_FPS_D (info));
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun   return TRUE;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun static gboolean
gst_mpp_enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)718*4882a593Smuzhiyun gst_mpp_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
721*4882a593Smuzhiyun   GstStructure *config, *params;
722*4882a593Smuzhiyun   GstVideoAlignment align;
723*4882a593Smuzhiyun   GstBufferPool *pool;
724*4882a593Smuzhiyun   GstVideoInfo info;
725*4882a593Smuzhiyun   GstCaps *caps;
726*4882a593Smuzhiyun   guint size;
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "propose allocation");
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun   gst_query_parse_allocation (query, &caps, NULL);
731*4882a593Smuzhiyun   if (caps == NULL)
732*4882a593Smuzhiyun     return FALSE;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun   if (!gst_video_info_from_caps (&info, caps))
735*4882a593Smuzhiyun     return FALSE;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun   gst_mpp_enc_video_info_align (&info);
738*4882a593Smuzhiyun   size = GST_VIDEO_INFO_SIZE (&info);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun   gst_video_alignment_reset (&align);
741*4882a593Smuzhiyun   align.padding_right = gst_mpp_get_pixel_stride (&info) -
742*4882a593Smuzhiyun       GST_VIDEO_INFO_WIDTH (&info);
743*4882a593Smuzhiyun   align.padding_bottom = GST_MPP_VIDEO_INFO_VSTRIDE (&info) -
744*4882a593Smuzhiyun       GST_VIDEO_INFO_HEIGHT (&info);
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun   /* Expose alignment to video-meta */
747*4882a593Smuzhiyun   params = gst_structure_new ("video-meta",
748*4882a593Smuzhiyun       "padding-top", G_TYPE_UINT, align.padding_top,
749*4882a593Smuzhiyun       "padding-bottom", G_TYPE_UINT, align.padding_bottom,
750*4882a593Smuzhiyun       "padding-left", G_TYPE_UINT, align.padding_left,
751*4882a593Smuzhiyun       "padding-right", G_TYPE_UINT, align.padding_right, NULL);
752*4882a593Smuzhiyun   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, params);
753*4882a593Smuzhiyun   gst_structure_free (params);
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun   pool = gst_video_buffer_pool_new ();
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun   config = gst_buffer_pool_get_config (pool);
758*4882a593Smuzhiyun   gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
759*4882a593Smuzhiyun   gst_buffer_pool_config_set_allocator (config, self->allocator, NULL);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun   /* Expose alignment to pool */
762*4882a593Smuzhiyun   gst_buffer_pool_config_add_option (config,
763*4882a593Smuzhiyun       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
764*4882a593Smuzhiyun   gst_buffer_pool_config_set_video_alignment (config, &align);
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun   gst_buffer_pool_set_config (pool, config);
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun   gst_query_add_allocation_pool (query, pool, size, MPP_PENDING_MAX, 0);
769*4882a593Smuzhiyun   gst_query_add_allocation_param (query, self->allocator, NULL);
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun   gst_object_unref (pool);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
774*4882a593Smuzhiyun       query);
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun static GstBuffer *
gst_mpp_enc_convert(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)778*4882a593Smuzhiyun gst_mpp_enc_convert (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
781*4882a593Smuzhiyun   GstVideoInfo src_info = self->input_state->info;
782*4882a593Smuzhiyun   GstVideoInfo *dst_info = &self->info;
783*4882a593Smuzhiyun   GstVideoFrame src_frame, dst_frame;
784*4882a593Smuzhiyun   GstBuffer *outbuf, *inbuf;
785*4882a593Smuzhiyun   GstMemory *in_mem, *out_mem;
786*4882a593Smuzhiyun   GstVideoMeta *meta;
787*4882a593Smuzhiyun   gsize size, maxsize, offset;
788*4882a593Smuzhiyun   guint i;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun   inbuf = frame->input_buffer;
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun   meta = gst_buffer_get_video_meta (inbuf);
793*4882a593Smuzhiyun   if (meta) {
794*4882a593Smuzhiyun     for (i = 0; i < meta->n_planes; i++) {
795*4882a593Smuzhiyun       GST_VIDEO_INFO_PLANE_STRIDE (&src_info, i) = meta->stride[i];
796*4882a593Smuzhiyun       GST_VIDEO_INFO_PLANE_OFFSET (&src_info, i) = meta->offset[i];
797*4882a593Smuzhiyun     }
798*4882a593Smuzhiyun   }
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun   size = gst_buffer_get_sizes (inbuf, &offset, &maxsize);
801*4882a593Smuzhiyun   if (size < GST_VIDEO_INFO_SIZE (&src_info)) {
802*4882a593Smuzhiyun     GST_ERROR_OBJECT (self, "input buffer too small (%" G_GSIZE_FORMAT
803*4882a593Smuzhiyun         " < %" G_GSIZE_FORMAT ")", size, GST_VIDEO_INFO_SIZE (&src_info));
804*4882a593Smuzhiyun     return NULL;
805*4882a593Smuzhiyun   }
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun   outbuf = gst_buffer_new ();
808*4882a593Smuzhiyun   if (!outbuf)
809*4882a593Smuzhiyun     goto err;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun   gst_buffer_copy_into (outbuf, inbuf,
812*4882a593Smuzhiyun       GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, 0);
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun   gst_buffer_add_video_meta_full (outbuf, GST_VIDEO_FRAME_FLAG_NONE,
815*4882a593Smuzhiyun       GST_VIDEO_INFO_FORMAT (dst_info),
816*4882a593Smuzhiyun       GST_VIDEO_INFO_WIDTH (dst_info), GST_VIDEO_INFO_HEIGHT (dst_info),
817*4882a593Smuzhiyun       GST_VIDEO_INFO_N_PLANES (dst_info), dst_info->offset, dst_info->stride);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun   if (self->rotation || !gst_mpp_enc_video_info_matched (&src_info, dst_info))
820*4882a593Smuzhiyun     goto convert;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun   if (gst_buffer_n_memory (inbuf) != 1)
823*4882a593Smuzhiyun     goto convert;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun   in_mem = gst_buffer_peek_memory (inbuf, 0);
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun   out_mem = gst_mpp_allocator_import_gst_memory (self->allocator, in_mem);
828*4882a593Smuzhiyun   if (!out_mem)
829*4882a593Smuzhiyun     goto convert;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun   gst_buffer_append_memory (outbuf, out_mem);
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun   /* Keep a ref of the original memory */
834*4882a593Smuzhiyun   gst_buffer_append_memory (outbuf, gst_memory_ref (in_mem));
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "using imported buffer");
837*4882a593Smuzhiyun   return outbuf;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun convert:
840*4882a593Smuzhiyun   out_mem = gst_allocator_alloc (self->allocator,
841*4882a593Smuzhiyun       GST_VIDEO_INFO_SIZE (dst_info), NULL);
842*4882a593Smuzhiyun   if (!out_mem)
843*4882a593Smuzhiyun     goto err;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun   gst_buffer_append_memory (outbuf, out_mem);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun #ifdef HAVE_RGA
848*4882a593Smuzhiyun   if (gst_mpp_use_rga () &&
849*4882a593Smuzhiyun       gst_mpp_rga_convert (inbuf, &src_info, out_mem, dst_info,
850*4882a593Smuzhiyun           self->rotation)) {
851*4882a593Smuzhiyun     GST_DEBUG_OBJECT (self, "using RGA converted buffer");
852*4882a593Smuzhiyun     return outbuf;
853*4882a593Smuzhiyun   }
854*4882a593Smuzhiyun #endif
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun   if (self->rotation ||
857*4882a593Smuzhiyun       GST_VIDEO_INFO_FORMAT (&src_info) != GST_VIDEO_INFO_FORMAT (dst_info))
858*4882a593Smuzhiyun     goto err;
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun   if (gst_video_frame_map (&src_frame, &src_info, inbuf, GST_MAP_READ)) {
861*4882a593Smuzhiyun     if (gst_video_frame_map (&dst_frame, dst_info, outbuf, GST_MAP_WRITE)) {
862*4882a593Smuzhiyun       if (!gst_video_frame_copy (&dst_frame, &src_frame)) {
863*4882a593Smuzhiyun         gst_video_frame_unmap (&dst_frame);
864*4882a593Smuzhiyun         gst_video_frame_unmap (&src_frame);
865*4882a593Smuzhiyun         goto err;
866*4882a593Smuzhiyun       }
867*4882a593Smuzhiyun       gst_video_frame_unmap (&dst_frame);
868*4882a593Smuzhiyun     }
869*4882a593Smuzhiyun     gst_video_frame_unmap (&src_frame);
870*4882a593Smuzhiyun   }
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "using software converted buffer");
873*4882a593Smuzhiyun   return outbuf;
874*4882a593Smuzhiyun err:
875*4882a593Smuzhiyun   if (outbuf)
876*4882a593Smuzhiyun     gst_buffer_unref (outbuf);
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun   GST_ERROR_OBJECT (self, "failed to convert frame");
879*4882a593Smuzhiyun   return NULL;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun static gboolean
gst_mpp_enc_force_keyframe(GstVideoEncoder * encoder,gboolean keyframe)883*4882a593Smuzhiyun gst_mpp_enc_force_keyframe (GstVideoEncoder * encoder, gboolean keyframe)
884*4882a593Smuzhiyun {
885*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun   /* HACK: Use gop(1) to force keyframe */
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun   if (!keyframe) {
890*4882a593Smuzhiyun     self->prop_dirty = TRUE;
891*4882a593Smuzhiyun     return gst_mpp_enc_apply_properties (encoder);
892*4882a593Smuzhiyun   }
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun   GST_INFO_OBJECT (self, "forcing keyframe");
895*4882a593Smuzhiyun   mpp_enc_cfg_set_s32 (self->mpp_cfg, "rc:gop", 1);
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun   if (self->mpi->control (self->mpp_ctx, MPP_ENC_SET_CFG, self->mpp_cfg)) {
898*4882a593Smuzhiyun     GST_WARNING_OBJECT (self, "failed to set enc cfg");
899*4882a593Smuzhiyun     return FALSE;
900*4882a593Smuzhiyun   }
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun   return TRUE;
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun static void
gst_mpp_enc_loop(GstVideoEncoder * encoder)906*4882a593Smuzhiyun gst_mpp_enc_loop (GstVideoEncoder * encoder)
907*4882a593Smuzhiyun {
908*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
909*4882a593Smuzhiyun   GstVideoCodecFrame *frame;
910*4882a593Smuzhiyun   GstBuffer *buffer;
911*4882a593Smuzhiyun   GstMemory *mem;
912*4882a593Smuzhiyun   MppFrame mframe;
913*4882a593Smuzhiyun   MppPacket mpkt = NULL;
914*4882a593Smuzhiyun   MppBuffer mbuf;
915*4882a593Smuzhiyun   gboolean keyframe;
916*4882a593Smuzhiyun   gint pkt_size;
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun   GST_MPP_ENC_WAIT (encoder, self->pending_frames || self->flushing);
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun   if (self->flushing && !self->pending_frames)
923*4882a593Smuzhiyun     goto flushing;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun   frame = gst_video_encoder_get_oldest_frame (encoder);
926*4882a593Smuzhiyun   self->pending_frames--;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun   GST_MPP_ENC_BROADCAST (encoder);
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun   /* HACK: get the converted input buffer from frame->output_buffer */
931*4882a593Smuzhiyun   mem = gst_buffer_peek_memory (frame->output_buffer, 0);
932*4882a593Smuzhiyun   mbuf = gst_mpp_mpp_buffer_from_gst_memory (mem);
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun   mframe = self->mpp_frame;
935*4882a593Smuzhiyun   mpp_frame_set_buffer (mframe, mbuf);
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun   keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
938*4882a593Smuzhiyun   if (keyframe)
939*4882a593Smuzhiyun     gst_mpp_enc_force_keyframe (encoder, TRUE);
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun   /* Encode one frame */
942*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
943*4882a593Smuzhiyun   if (!self->mpi->encode_put_frame (self->mpp_ctx, mframe))
944*4882a593Smuzhiyun     self->mpi->encode_get_packet (self->mpp_ctx, &mpkt);
945*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun   if (keyframe)
948*4882a593Smuzhiyun     gst_mpp_enc_force_keyframe (encoder, FALSE);
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun   if (!mpkt)
951*4882a593Smuzhiyun     goto error;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun   pkt_size = mpp_packet_get_length (mpkt);
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun   mbuf = mpp_packet_get_buffer (mpkt);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun   if (self->zero_copy_pkt) {
958*4882a593Smuzhiyun     buffer = gst_buffer_new ();
959*4882a593Smuzhiyun     if (!buffer)
960*4882a593Smuzhiyun       goto error;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun     /* Allocated from the same DRM allocator in MPP */
963*4882a593Smuzhiyun     mpp_buffer_set_index (mbuf, gst_mpp_allocator_get_index (self->allocator));
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun     mem = gst_mpp_allocator_import_mppbuf (self->allocator, mbuf);
966*4882a593Smuzhiyun     if (!mem) {
967*4882a593Smuzhiyun       gst_buffer_unref (buffer);
968*4882a593Smuzhiyun       goto error;
969*4882a593Smuzhiyun     }
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun     gst_memory_resize (mem, 0, pkt_size);
972*4882a593Smuzhiyun     gst_buffer_append_memory (buffer, mem);
973*4882a593Smuzhiyun   } else {
974*4882a593Smuzhiyun     buffer = gst_video_encoder_allocate_output_buffer (encoder, pkt_size);
975*4882a593Smuzhiyun     if (!buffer)
976*4882a593Smuzhiyun       goto error;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun     gst_buffer_fill (buffer, 0, mpp_buffer_get_ptr (mbuf), pkt_size);
979*4882a593Smuzhiyun   }
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun   gst_buffer_replace (&frame->output_buffer, buffer);
982*4882a593Smuzhiyun   gst_buffer_unref (buffer);
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun   if (self->flushing && !self->draining)
985*4882a593Smuzhiyun     goto drop;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "finish frame ts=%" GST_TIME_FORMAT,
988*4882a593Smuzhiyun       GST_TIME_ARGS (frame->pts));
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun   gst_video_encoder_finish_frame (encoder, frame);
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun out:
993*4882a593Smuzhiyun   if (mpkt)
994*4882a593Smuzhiyun     mpp_packet_deinit (&mpkt);
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun   if (self->task_ret != GST_FLOW_OK) {
997*4882a593Smuzhiyun     GST_DEBUG_OBJECT (self, "leaving output thread: %s",
998*4882a593Smuzhiyun         gst_flow_get_name (self->task_ret));
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun     gst_pad_pause_task (encoder->srcpad);
1001*4882a593Smuzhiyun   }
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1004*4882a593Smuzhiyun   return;
1005*4882a593Smuzhiyun flushing:
1006*4882a593Smuzhiyun   GST_INFO_OBJECT (self, "flushing");
1007*4882a593Smuzhiyun   self->task_ret = GST_FLOW_FLUSHING;
1008*4882a593Smuzhiyun   goto out;
1009*4882a593Smuzhiyun error:
1010*4882a593Smuzhiyun   GST_WARNING_OBJECT (self, "can't process this frame");
1011*4882a593Smuzhiyun   goto drop;
1012*4882a593Smuzhiyun drop:
1013*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "drop frame");
1014*4882a593Smuzhiyun   gst_buffer_replace (&frame->output_buffer, NULL);
1015*4882a593Smuzhiyun   gst_video_encoder_finish_frame (encoder, frame);
1016*4882a593Smuzhiyun   goto out;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun static GstFlowReturn
gst_mpp_enc_handle_frame(GstVideoEncoder * encoder,GstVideoCodecFrame * frame)1020*4882a593Smuzhiyun gst_mpp_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
1021*4882a593Smuzhiyun {
1022*4882a593Smuzhiyun   GstMppEnc *self = GST_MPP_ENC (encoder);
1023*4882a593Smuzhiyun   GstBuffer *buffer;
1024*4882a593Smuzhiyun   GstFlowReturn ret = GST_FLOW_OK;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun   GST_DEBUG_OBJECT (self, "handling frame %d", frame->system_frame_number);
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun   GST_MPP_ENC_LOCK (encoder);
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun   if (G_UNLIKELY (self->flushing))
1031*4882a593Smuzhiyun     goto flushing;
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun   if (G_UNLIKELY (!GST_MPP_ENC_TASK_STARTED (encoder))) {
1034*4882a593Smuzhiyun     GST_DEBUG_OBJECT (self, "starting encoding thread");
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun     gst_pad_start_task (encoder->srcpad,
1037*4882a593Smuzhiyun         (GstTaskFunction) gst_mpp_enc_loop, encoder, NULL);
1038*4882a593Smuzhiyun   }
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1041*4882a593Smuzhiyun   buffer = gst_mpp_enc_convert (encoder, frame);
1042*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1043*4882a593Smuzhiyun   if (G_UNLIKELY (!buffer))
1044*4882a593Smuzhiyun     goto not_negotiated;
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun   /* HACK: store the converted input buffer in frame->output_buffer */
1047*4882a593Smuzhiyun   frame->output_buffer = buffer;
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun   /* Avoid holding too much frames */
1050*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1051*4882a593Smuzhiyun   GST_MPP_ENC_WAIT (encoder, self->pending_frames < MPP_PENDING_MAX
1052*4882a593Smuzhiyun       || self->flushing);
1053*4882a593Smuzhiyun   GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun   self->pending_frames++;
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun   GST_MPP_ENC_BROADCAST (encoder);
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun   gst_video_codec_frame_unref (frame);
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun   GST_MPP_ENC_UNLOCK (encoder);
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun   return self->task_ret;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun flushing:
1066*4882a593Smuzhiyun   GST_WARNING_OBJECT (self, "flushing");
1067*4882a593Smuzhiyun   ret = GST_FLOW_FLUSHING;
1068*4882a593Smuzhiyun   goto drop;
1069*4882a593Smuzhiyun not_negotiated:
1070*4882a593Smuzhiyun   GST_ERROR_OBJECT (self, "not negotiated");
1071*4882a593Smuzhiyun   ret = GST_FLOW_NOT_NEGOTIATED;
1072*4882a593Smuzhiyun   goto drop;
1073*4882a593Smuzhiyun drop:
1074*4882a593Smuzhiyun   GST_WARNING_OBJECT (self, "can't handle this frame");
1075*4882a593Smuzhiyun   gst_video_encoder_finish_frame (encoder, frame);
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun   GST_MPP_ENC_UNLOCK (encoder);
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun   return ret;
1080*4882a593Smuzhiyun }
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun static GstStateChangeReturn
gst_mpp_enc_change_state(GstElement * element,GstStateChange transition)1083*4882a593Smuzhiyun gst_mpp_enc_change_state (GstElement * element, GstStateChange transition)
1084*4882a593Smuzhiyun {
1085*4882a593Smuzhiyun   GstVideoEncoder *encoder = GST_VIDEO_ENCODER (element);
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun   if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) {
1088*4882a593Smuzhiyun     GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1089*4882a593Smuzhiyun     gst_mpp_enc_reset (encoder, FALSE, TRUE);
1090*4882a593Smuzhiyun     GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1091*4882a593Smuzhiyun   }
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun   return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun static void
gst_mpp_enc_init(GstMppEnc * self)1097*4882a593Smuzhiyun gst_mpp_enc_init (GstMppEnc * self)
1098*4882a593Smuzhiyun {
1099*4882a593Smuzhiyun   self->mpp_type = MPP_VIDEO_CodingUnused;
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun   self->header_mode = DEFAULT_PROP_HEADER_MODE;
1102*4882a593Smuzhiyun   self->sei_mode = DEFAULT_PROP_SEI_MODE;
1103*4882a593Smuzhiyun   self->rc_mode = DEFAULT_PROP_RC_MODE;
1104*4882a593Smuzhiyun   self->rotation = DEFAULT_PROP_ROTATION;
1105*4882a593Smuzhiyun   self->gop = DEFAULT_PROP_GOP;
1106*4882a593Smuzhiyun   self->max_reenc = DEFAULT_PROP_MAX_REENC;
1107*4882a593Smuzhiyun   self->bps = DEFAULT_PROP_BPS;
1108*4882a593Smuzhiyun   self->bps_min = DEFAULT_PROP_BPS_MIN;
1109*4882a593Smuzhiyun   self->bps_max = DEFAULT_PROP_BPS_MAX;
1110*4882a593Smuzhiyun   self->zero_copy_pkt = DEFAULT_PROP_ZERO_COPY_PKT;
1111*4882a593Smuzhiyun   self->arm_afbc = DEFAULT_PROP_ARM_AFBC;
1112*4882a593Smuzhiyun   self->prop_dirty = TRUE;
1113*4882a593Smuzhiyun }
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun #define GST_TYPE_MPP_ENC_HEADER_MODE (gst_mpp_enc_header_mode_get_type ())
1116*4882a593Smuzhiyun static GType
gst_mpp_enc_header_mode_get_type(void)1117*4882a593Smuzhiyun gst_mpp_enc_header_mode_get_type (void)
1118*4882a593Smuzhiyun {
1119*4882a593Smuzhiyun   static GType header_mode = 0;
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun   if (!header_mode) {
1122*4882a593Smuzhiyun     static const GEnumValue modes[] = {
1123*4882a593Smuzhiyun       {MPP_ENC_HEADER_MODE_DEFAULT, "Only in the first frame", "first-frame"},
1124*4882a593Smuzhiyun       {MPP_ENC_HEADER_MODE_EACH_IDR, "In every IDR frames", "each-idr"},
1125*4882a593Smuzhiyun       {0, NULL, NULL}
1126*4882a593Smuzhiyun     };
1127*4882a593Smuzhiyun     header_mode = g_enum_register_static ("MppEncHeaderMode", modes);
1128*4882a593Smuzhiyun   }
1129*4882a593Smuzhiyun   return header_mode;
1130*4882a593Smuzhiyun }
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun #define GST_TYPE_MPP_ENC_SEI_MODE (gst_mpp_enc_sei_mode_get_type ())
1133*4882a593Smuzhiyun static GType
gst_mpp_enc_sei_mode_get_type(void)1134*4882a593Smuzhiyun gst_mpp_enc_sei_mode_get_type (void)
1135*4882a593Smuzhiyun {
1136*4882a593Smuzhiyun   static GType sei_mode = 0;
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun   if (!sei_mode) {
1139*4882a593Smuzhiyun     static const GEnumValue modes[] = {
1140*4882a593Smuzhiyun       {MPP_ENC_SEI_MODE_DISABLE, "SEI disabled", "disable"},
1141*4882a593Smuzhiyun       {MPP_ENC_SEI_MODE_ONE_SEQ, "One SEI per sequence", "one-seq"},
1142*4882a593Smuzhiyun       {MPP_ENC_SEI_MODE_ONE_FRAME, "One SEI per frame(if changed)",
1143*4882a593Smuzhiyun           "one-frame"},
1144*4882a593Smuzhiyun       {0, NULL, NULL}
1145*4882a593Smuzhiyun     };
1146*4882a593Smuzhiyun     sei_mode = g_enum_register_static ("GstMppEncSeiMode", modes);
1147*4882a593Smuzhiyun   }
1148*4882a593Smuzhiyun   return sei_mode;
1149*4882a593Smuzhiyun }
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun #define GST_TYPE_MPP_ENC_RC_MODE (gst_mpp_enc_rc_mode_get_type ())
1152*4882a593Smuzhiyun static GType
gst_mpp_enc_rc_mode_get_type(void)1153*4882a593Smuzhiyun gst_mpp_enc_rc_mode_get_type (void)
1154*4882a593Smuzhiyun {
1155*4882a593Smuzhiyun   static GType rc_mode = 0;
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun   if (!rc_mode) {
1158*4882a593Smuzhiyun     static const GEnumValue modes[] = {
1159*4882a593Smuzhiyun       {MPP_ENC_RC_MODE_VBR, "Variable bitrate", "vbr"},
1160*4882a593Smuzhiyun       {MPP_ENC_RC_MODE_CBR, "Constant bitrate", "cbr"},
1161*4882a593Smuzhiyun       {MPP_ENC_RC_MODE_FIXQP, "Fixed QP", "fixqp"},
1162*4882a593Smuzhiyun       {0, NULL, NULL}
1163*4882a593Smuzhiyun     };
1164*4882a593Smuzhiyun     rc_mode = g_enum_register_static ("GstMppEncRcMode", modes);
1165*4882a593Smuzhiyun   }
1166*4882a593Smuzhiyun   return rc_mode;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun #ifdef HAVE_RGA
1170*4882a593Smuzhiyun #define GST_TYPE_MPP_ENC_ROTATION (gst_mpp_enc_rotation_get_type ())
1171*4882a593Smuzhiyun static GType
gst_mpp_enc_rotation_get_type(void)1172*4882a593Smuzhiyun gst_mpp_enc_rotation_get_type (void)
1173*4882a593Smuzhiyun {
1174*4882a593Smuzhiyun   static GType rotation = 0;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun   if (!rotation) {
1177*4882a593Smuzhiyun     static const GEnumValue rotations[] = {
1178*4882a593Smuzhiyun       {0, "Rotate 0", "0"},
1179*4882a593Smuzhiyun       {90, "Rotate 90", "90"},
1180*4882a593Smuzhiyun       {180, "Rotate 180", "180"},
1181*4882a593Smuzhiyun       {270, "Rotate 270", "270"},
1182*4882a593Smuzhiyun       {0, NULL, NULL}
1183*4882a593Smuzhiyun     };
1184*4882a593Smuzhiyun     rotation = g_enum_register_static ("GstMppEncRotation", rotations);
1185*4882a593Smuzhiyun   }
1186*4882a593Smuzhiyun   return rotation;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun #endif
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun static void
gst_mpp_enc_class_init(GstMppEncClass * klass)1191*4882a593Smuzhiyun gst_mpp_enc_class_init (GstMppEncClass * klass)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun   GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
1194*4882a593Smuzhiyun   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1195*4882a593Smuzhiyun   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "mppenc", 0, "MPP encoder");
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun   encoder_class->start = GST_DEBUG_FUNCPTR (gst_mpp_enc_start);
1200*4882a593Smuzhiyun   encoder_class->stop = GST_DEBUG_FUNCPTR (gst_mpp_enc_stop);
1201*4882a593Smuzhiyun   encoder_class->flush = GST_DEBUG_FUNCPTR (gst_mpp_enc_flush);
1202*4882a593Smuzhiyun   encoder_class->finish = GST_DEBUG_FUNCPTR (gst_mpp_enc_finish);
1203*4882a593Smuzhiyun   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_mpp_enc_set_format);
1204*4882a593Smuzhiyun   encoder_class->propose_allocation =
1205*4882a593Smuzhiyun       GST_DEBUG_FUNCPTR (gst_mpp_enc_propose_allocation);
1206*4882a593Smuzhiyun   encoder_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mpp_enc_handle_frame);
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_mpp_enc_set_property);
1209*4882a593Smuzhiyun   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_mpp_enc_get_property);
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_HEADER_MODE,
1212*4882a593Smuzhiyun       g_param_spec_enum ("header-mode", "Header mode",
1213*4882a593Smuzhiyun           "Header mode",
1214*4882a593Smuzhiyun           GST_TYPE_MPP_ENC_HEADER_MODE, DEFAULT_PROP_HEADER_MODE,
1215*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_SEI_MODE,
1218*4882a593Smuzhiyun       g_param_spec_enum ("sei-mode", "SEI mode",
1219*4882a593Smuzhiyun           "SEI mode",
1220*4882a593Smuzhiyun           GST_TYPE_MPP_ENC_SEI_MODE, DEFAULT_PROP_SEI_MODE,
1221*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_RC_MODE,
1224*4882a593Smuzhiyun       g_param_spec_enum ("rc-mode", "RC mode",
1225*4882a593Smuzhiyun           "RC mode",
1226*4882a593Smuzhiyun           GST_TYPE_MPP_ENC_RC_MODE, DEFAULT_PROP_RC_MODE,
1227*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun #ifdef HAVE_RGA
1230*4882a593Smuzhiyun   if (!gst_mpp_use_rga ())
1231*4882a593Smuzhiyun     goto no_rga;
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_ROTATION,
1234*4882a593Smuzhiyun       g_param_spec_enum ("rotation", "Rotation",
1235*4882a593Smuzhiyun           "Rotation",
1236*4882a593Smuzhiyun           GST_TYPE_MPP_ENC_ROTATION, DEFAULT_PROP_ROTATION,
1237*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_WIDTH,
1240*4882a593Smuzhiyun       g_param_spec_uint ("width", "Width",
1241*4882a593Smuzhiyun           "Width (0 = original)",
1242*4882a593Smuzhiyun           0, G_MAXINT, DEFAULT_PROP_WIDTH,
1243*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_HEIGHT,
1246*4882a593Smuzhiyun       g_param_spec_uint ("height", "Height",
1247*4882a593Smuzhiyun           "Height (0 = original)",
1248*4882a593Smuzhiyun           0, G_MAXINT, DEFAULT_PROP_HEIGHT,
1249*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun no_rga:
1252*4882a593Smuzhiyun #endif
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_GOP,
1255*4882a593Smuzhiyun       g_param_spec_int ("gop", "Group of pictures",
1256*4882a593Smuzhiyun           "Group of pictures starting with I frame (-1 = FPS, 1 = all I frames)",
1257*4882a593Smuzhiyun           -1, G_MAXINT, DEFAULT_PROP_GOP,
1258*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_MAX_REENC,
1261*4882a593Smuzhiyun       g_param_spec_uint ("max-reenc", "Max re-encode times",
1262*4882a593Smuzhiyun           "Max re-encode times for one frame",
1263*4882a593Smuzhiyun           0, 3, DEFAULT_PROP_MAX_REENC,
1264*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_BPS,
1267*4882a593Smuzhiyun       g_param_spec_uint ("bps", "Target BPS",
1268*4882a593Smuzhiyun           "Target BPS (0 = auto calculate)",
1269*4882a593Smuzhiyun           0, G_MAXINT, DEFAULT_PROP_BPS,
1270*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_BPS_MIN,
1273*4882a593Smuzhiyun       g_param_spec_uint ("bps-min", "Min BPS",
1274*4882a593Smuzhiyun           "Min BPS (0 = auto calculate)",
1275*4882a593Smuzhiyun           0, G_MAXINT, DEFAULT_PROP_BPS_MIN,
1276*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1277*4882a593Smuzhiyun 
1278*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_BPS_MAX,
1279*4882a593Smuzhiyun       g_param_spec_uint ("bps-max", "Max BPS",
1280*4882a593Smuzhiyun           "Max BPS (0 = auto calculate)",
1281*4882a593Smuzhiyun           0, G_MAXINT, DEFAULT_PROP_BPS_MAX,
1282*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_ZERO_COPY_PKT,
1285*4882a593Smuzhiyun       g_param_spec_boolean ("zero-copy-pkt", "Zero-copy encoded packet",
1286*4882a593Smuzhiyun           "Zero-copy encoded packet", DEFAULT_PROP_ZERO_COPY_PKT,
1287*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun   if (g_getenv ("GST_MPPENC_DEFAULT_ARM_AFBC"))
1290*4882a593Smuzhiyun     DEFAULT_PROP_ARM_AFBC = TRUE;
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun   g_object_class_install_property (gobject_class, PROP_ARM_AFBC,
1293*4882a593Smuzhiyun       g_param_spec_boolean ("arm-afbc", "ARM AFBC",
1294*4882a593Smuzhiyun           "Input is ARM AFBC compressed format", DEFAULT_PROP_ARM_AFBC,
1295*4882a593Smuzhiyun           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun   element_class->change_state = GST_DEBUG_FUNCPTR (gst_mpp_enc_change_state);
1298*4882a593Smuzhiyun }
1299