h264encoder: auto-detect stream-format: avc/byte-stream by next linked-pad's caps
[vaapi:windyuan-gstreamer-vaapi.git] / gst / vaapiencode / gstvaapimpeg4encoder.c
1 /*
2  *  gstvaapimpeg4encoder.c - MPEG-4 encoder
3  *
4  *  Copyright (C) 2011 Intel Corporation
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library 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 this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 #include "gstvaapimpeg4encoder.h"
23
24 #include <string.h>
25 #include "gst/gstclock.h"
26
27 #include "gst/vaapi/gstvaapiobject.h"
28 #include "gst/vaapi/gstvaapiobject_priv.h"
29 #include "gst/vaapi/gstvaapicontext.h"
30 #include "gst/vaapi/gstvaapisurface.h"
31 #include "gst/vaapi/gstvaapivideobuffer.h"
32 #include "gst/vaapi/gstvaapidisplay_priv.h"
33
34 GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg4_encoder_debug);
35 #define GST_CAT_DEFAULT gst_vaapi_mpeg4_encoder_debug
36
37
38 struct _GstMPEG4EncoderPrivate {
39   GstVaapiSurface  *ref_surface;  /* reference buffer*/
40   GstVaapiSurface  *recon_surface; /* reconstruct buffer*/
41
42   VABufferID        seq_parameter;
43   VABufferID        pic_parameter;
44   VABufferID        slice_parameter;
45
46   GstBuffer        *codec_data;
47 };
48
49 G_DEFINE_TYPE(GstMPEG4Encoder, gst_mpeg4_encoder, GST_TYPE_VAAPI_BASE_ENCODER);
50
51 /*
52 static EncoderStatus gst_mpeg4_encoder_flush(GstVaapiEncoder* encoder,
53                          GstVaapiDisplay *display, GstVaapiContext *context,
54                          GList **coded_pics);
55 */
56 static EncoderStatus gst_mpeg4_encoder_get_codec_data(
57                          GstVaapiEncoder *encoder, GstBuffer **buffer);
58 static gboolean      gst_mpeg4_validate_parameters(GstVaapiBaseEncoder *encoder);
59 static gboolean      gst_mpeg4_encoder_release_resource(
60                          GstVaapiBaseEncoder* encoder, GstVaapiDisplay *display,
61                          GstVaapiContext *context);
62 static void          gst_mpeg4_notify_frame(GstVaapiBaseEncoder *encoder,
63                          guint8 *buf, guint32 size);
64
65 static EncoderStatus gst_mpeg4_encoder_rendering(GstVaapiBaseEncoder *encoder,
66                        GstVaapiDisplay *display, GstVaapiContext *context,
67                        GstVaapiSurface *surface, guint frame_index,
68                        VABufferID coded_buf, gboolean *is_key);
69
70
71 static void          gst_mpeg4_encoder_class_init(GstMPEG4EncoderClass *klass);
72 static void          gst_mpeg4_encoder_init(GstMPEG4Encoder *encoder);
73 static void          gst_mpeg4_encoder_finalize(GObject *object);
74
75 static gboolean      mpeg4_encoder_generate_codec_data(const guint8 *in_buffer,
76                                           guint32 in_size, GstBuffer **out_buffer);
77
78 GstMPEG4Encoder *
79 gst_mpeg4_encoder_new(void)
80 {
81   return GST_MPEG4_ENCODER(g_object_new(GST_TYPE_MPEG4_ENCODER, NULL));
82 }
83
84
85 static void
86 gst_mpeg4_encoder_class_init(GstMPEG4EncoderClass *klass)
87 {
88   GObjectClass * const object_class = G_OBJECT_CLASS(klass);
89   GstVaapiEncoderClass * const encoder_class = GST_VAAPI_ENCODER_CLASS(klass);
90   GstVaapiBaseEncoderClass * const base_class = GST_VAAPI_BASE_ENCODER_CLASS(klass);
91
92   g_type_class_add_private(klass, sizeof(GstMPEG4EncoderPrivate));
93
94   GST_DEBUG_CATEGORY_INIT (gst_vaapi_mpeg4_encoder_debug, "gst_va_mpeg4_encoder", 0,
95       "gst_va_mpeg4_encoder element");
96
97   object_class->finalize = gst_mpeg4_encoder_finalize;
98
99   base_class->validate_attributes = gst_mpeg4_validate_parameters;
100   base_class->pre_alloc_resource  = NULL;
101   base_class->release_resource    = gst_mpeg4_encoder_release_resource;
102   base_class->render_frame = gst_mpeg4_encoder_rendering;
103   base_class->notify_frame = gst_mpeg4_notify_frame;
104   base_class->copy_coded_frame = NULL;
105
106   /*
107   encoder_class->flush = gst_mpeg4_encoder_flush;
108   */
109   encoder_class->get_codec_data = gst_mpeg4_encoder_get_codec_data;
110 }
111
112 static void
113 gst_mpeg4_encoder_init(GstMPEG4Encoder *mpeg4_encoder)
114 {
115   GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
116   ENCODER_ASSERT(mpeg4_prv);
117
118   /* init public */
119   mpeg4_encoder->profile = VAProfileMPEG4Simple;
120   mpeg4_encoder->bitrate = 0;
121   mpeg4_encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
122   mpeg4_encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
123   mpeg4_encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
124
125   gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(mpeg4_encoder), TRUE);
126   /* init private */
127   mpeg4_prv->ref_surface = NULL;
128   mpeg4_prv->recon_surface = NULL;
129
130   mpeg4_prv->seq_parameter = VA_INVALID_ID;
131   mpeg4_prv->pic_parameter = VA_INVALID_ID;
132   mpeg4_prv->slice_parameter = VA_INVALID_ID;
133
134   mpeg4_prv->codec_data = NULL;
135 }
136
137 static void
138 gst_mpeg4_encoder_finalize(GObject *object)
139 {
140   /*free private buffers*/
141   GstVaapiEncoder *encoder = GST_VAAPI_ENCODER(object);
142
143   if (gst_vaapi_encoder_get_state(encoder) != VAAPI_ENC_NULL) {
144     gst_vaapi_encoder_uninitialize(encoder);
145   }
146   G_OBJECT_CLASS(gst_mpeg4_encoder_parent_class)->finalize(object);
147 }
148
149 gboolean
150 gst_mpeg4_validate_parameters(GstVaapiBaseEncoder *encoder)
151 {
152   GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
153   if (!ENCODER_WIDTH(mpeg4_encoder) || !ENCODER_HEIGHT(mpeg4_encoder) || !ENCODER_FPS(mpeg4_encoder)) {
154     return FALSE;
155   }
156   if (VAProfileMPEG4Simple != mpeg4_encoder->profile && VAProfileMPEG4AdvancedSimple != mpeg4_encoder->profile) {
157     return FALSE;
158   }
159   gst_vaapi_base_encoder_set_va_profile(encoder, mpeg4_encoder->profile);
160
161   if (!mpeg4_encoder->intra_period) {
162     mpeg4_encoder->intra_period = MPEG4_DEFAULT_INTRA_PERIOD;
163   }
164   if (-1 == mpeg4_encoder->init_qp) {
165     mpeg4_encoder->init_qp = MPEG4_DEFAULT_INIT_QP;
166   }
167   if (-1 == mpeg4_encoder->min_qp) {
168     mpeg4_encoder->min_qp = MPEG4_DEFAULT_MIN_QP;
169   }
170
171   /* default compress ratio 1: (4*8*1.5) */
172   if (!mpeg4_encoder->bitrate) {
173     mpeg4_encoder->bitrate = ENCODER_WIDTH(mpeg4_encoder)*ENCODER_HEIGHT(mpeg4_encoder)*ENCODER_FPS(mpeg4_encoder)/4;
174   }
175   return TRUE;
176
177 }
178
179 static void
180 mpeg4_release_parameters(GstMPEG4Encoder *mpeg4_encoder, GstVaapiDisplay *display)
181 {
182   GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
183   VADisplay va_dpy = gst_vaapi_display_get_display(display);
184   VAStatus va_status = VA_STATUS_SUCCESS;
185
186   VAAPI_UNUSED_ARG(va_status);
187
188   if (VA_INVALID_ID != mpeg4_prv->seq_parameter) {
189     va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->seq_parameter);
190     mpeg4_prv->seq_parameter = VA_INVALID_ID;
191   }
192   if (VA_INVALID_ID != mpeg4_prv->pic_parameter) {
193     va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->pic_parameter);
194     mpeg4_prv->pic_parameter = VA_INVALID_ID;
195   }
196   if (VA_INVALID_ID != mpeg4_prv->slice_parameter) {
197     va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->slice_parameter);
198     mpeg4_prv->slice_parameter = VA_INVALID_ID;
199   }
200 }
201
202 static gboolean
203 gst_mpeg4_encoder_release_resource(GstVaapiBaseEncoder* encoder,
204                        GstVaapiDisplay *display,
205                        GstVaapiContext *context)
206 {
207   GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
208   GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
209
210   mpeg4_release_parameters(mpeg4_encoder, display);
211
212   /*remove ref_surface*/
213   if (mpeg4_prv->ref_surface) {
214     if (context) {
215       gst_vaapi_context_put_surface(context, mpeg4_prv->ref_surface);
216     } else {
217       g_object_unref(mpeg4_prv->ref_surface);
218     }
219     mpeg4_prv->ref_surface = NULL;
220   }
221
222   /*remove recon_surface*/
223   if (mpeg4_prv->recon_surface) {
224     if (context) {
225       gst_vaapi_context_put_surface(context, mpeg4_prv->recon_surface);
226     } else {
227       g_object_unref(mpeg4_prv->recon_surface);
228     }
229     mpeg4_prv->recon_surface = NULL;
230   }
231
232   if (mpeg4_prv->codec_data) {
233     gst_buffer_unref(mpeg4_prv->codec_data);
234     mpeg4_prv->codec_data = NULL;
235   }
236
237   return TRUE;
238 }
239
240 static guint32
241 mpeg4_get_profile_level_indication(guint32 profile)
242 {
243   switch(profile) {
244   case VAProfileMPEG4Simple:
245     return MPEG4_DEFAULT_SIMPLE_PROFILE_AND_LEVEL;
246   case VAProfileMPEG4AdvancedSimple:
247     return MPEG4_DEFAULT_ADVANCED_SIMPLE_PROFILE_AND_LEVEL;
248   default:
249     return 0;
250   }
251   return 0;
252 }
253
254
255 static EncoderStatus
256 gst_mpeg4_encoder_rendering(GstVaapiBaseEncoder *encoder, GstVaapiDisplay *display,
257                        GstVaapiContext *context, GstVaapiSurface *surface,
258                        guint frame_index, VABufferID coded_buf, gboolean *is_key)
259 {
260   GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
261   GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(mpeg4_encoder);
262   VADisplay va_dpy = gst_vaapi_display_get_display(display);
263   VAContextID context_id = GST_VAAPI_OBJECT_ID(context);
264
265   VAStatus va_status = VA_STATUS_SUCCESS;
266   EncoderStatus ret = ENCODER_NO_ERROR;
267
268   *is_key = (frame_index % mpeg4_encoder->intra_period == 0);
269
270   /* initialize sequence parameter set, only first time */
271   if (VA_INVALID_ID == mpeg4_prv->seq_parameter) { /*only the first time*/
272     VAEncSequenceParameterBufferMPEG4 seq_mpeg4 = {0};
273
274     seq_mpeg4.profile_and_level_indication = mpeg4_get_profile_level_indication(mpeg4_encoder->profile);
275     seq_mpeg4.intra_period = mpeg4_encoder->intra_period;
276     seq_mpeg4.video_object_layer_width = ENCODER_WIDTH(mpeg4_encoder);
277     seq_mpeg4.video_object_layer_height = ENCODER_HEIGHT(mpeg4_encoder);
278     seq_mpeg4.vop_time_increment_resolution = ENCODER_FPS(mpeg4_encoder);
279     seq_mpeg4.fixed_vop_rate = MPEG4_DEFAULT_FIXED_VOP_RATE;
280     if (seq_mpeg4.fixed_vop_rate) {
281       seq_mpeg4.fixed_vop_time_increment = 1;
282     }
283     seq_mpeg4.bits_per_second = mpeg4_encoder->bitrate;
284     seq_mpeg4.frame_rate = ENCODER_FPS(mpeg4_encoder);
285     seq_mpeg4.initial_qp = mpeg4_encoder->init_qp;
286     seq_mpeg4.min_qp = mpeg4_encoder->min_qp; //mpeg4_encoder->min_qp;
287
288     va_status = vaCreateBuffer(va_dpy, context_id,
289                                VAEncSequenceParameterBufferType,
290                                sizeof(seq_mpeg4), 1, &seq_mpeg4, &mpeg4_prv->seq_parameter);
291     ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
292                          ENCODER_ENC_RES_ERR, "mpeg4 alloc seq-buffer failed.");
293     va_status = vaRenderPicture(va_dpy, context_id, &mpeg4_prv->seq_parameter, 1);
294     ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS == va_status,
295                          ENCODER_PICTURE_ERR,
296                          "mpeg4 vaRenderPicture seq-parameters failed.");
297   }
298
299   /* set reference and reconstructed surfaces */
300   if (!mpeg4_prv->ref_surface) {
301     mpeg4_prv->ref_surface = gst_vaapi_context_get_surface(context);
302     ENCODER_CHECK_STATUS(mpeg4_prv->ref_surface,
303                          ENCODER_SURFACE_ERR,
304                          "mpeg4 reference surface, mpeg4_pop_free_surface failed.");
305   }
306   if (!mpeg4_prv->recon_surface) {
307     mpeg4_prv->recon_surface = gst_vaapi_context_get_surface(context);
308     ENCODER_CHECK_STATUS(mpeg4_prv->recon_surface,
309                          ENCODER_SURFACE_ERR,
310                          "mpeg4 reconstructed surface, mpeg4_pop_free_surface failed.");
311   }
312
313   /* initialize picture, every time, every frame */
314   VAEncPictureParameterBufferMPEG4 pic_mpeg4 = {0};
315   pic_mpeg4.reference_picture = GST_VAAPI_OBJECT_ID(mpeg4_prv->ref_surface);
316   pic_mpeg4.reconstructed_picture = GST_VAAPI_OBJECT_ID(mpeg4_prv->recon_surface);
317   pic_mpeg4.coded_buf = coded_buf;
318   pic_mpeg4.picture_width = ENCODER_WIDTH(mpeg4_encoder);
319   pic_mpeg4.picture_height = ENCODER_HEIGHT(mpeg4_encoder);
320   if (0 == frame_index) {
321     pic_mpeg4.modulo_time_base = 0;
322   } else {
323     pic_mpeg4.modulo_time_base = ((frame_index%ENCODER_FPS(mpeg4_encoder)) == 0 ? 1 : 0);
324   }
325   pic_mpeg4.vop_time_increment = 301%ENCODER_FPS(mpeg4_encoder);
326   pic_mpeg4.picture_type = *is_key ? VAEncPictureTypeIntra : VAEncPictureTypePredictive;
327
328   if (VA_INVALID_ID != mpeg4_prv->pic_parameter) { /* destroy first*/
329     va_status = vaDestroyBuffer(va_dpy, mpeg4_prv->pic_parameter);
330     mpeg4_prv->pic_parameter = VA_INVALID_ID;
331   }
332
333   va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
334                                sizeof(pic_mpeg4), 1, &pic_mpeg4, &mpeg4_prv->pic_parameter);
335   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
336                        ENCODER_ENC_RES_ERR,
337                        "mpeg4 creating pic-param buffer failed.");
338   va_status = vaRenderPicture(va_dpy, context_id, &mpeg4_prv->pic_parameter, 1);
339   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
340                        ENCODER_PICTURE_ERR,
341                        "mpeg4 rendering pic-param buffer failed.");
342   /*initialize slice parameters, only ONE slice for mpeg4*/
343   VAEncSliceParameterBuffer slice_mpeg4 = { 0 };
344   slice_mpeg4.start_row_number = 0;
345   slice_mpeg4.slice_height = (ENCODER_HEIGHT(mpeg4_encoder)+15)/16; /*MB?*/
346   slice_mpeg4.slice_flags.bits.is_intra = *is_key;
347   slice_mpeg4.slice_flags.bits.disable_deblocking_filter_idc = 0;
348   if (VA_INVALID_ID != mpeg4_prv->slice_parameter) {
349     vaDestroyBuffer(va_dpy, mpeg4_prv->slice_parameter);
350     mpeg4_prv->slice_parameter = VA_INVALID_ID;
351   }
352
353   va_status = vaCreateBuffer(va_dpy,
354                              context_id,
355                              VAEncSliceParameterBufferType,
356                              sizeof(slice_mpeg4),
357                              1,
358                              &slice_mpeg4,
359                              &mpeg4_prv->slice_parameter);
360   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
361                        ENCODER_ENC_RES_ERR,
362                        "mpeg4 creating slice-parameters buffer failed.");
363
364   va_status = vaRenderPicture(va_dpy, context_id, &mpeg4_prv->slice_parameter, 1);
365   ENCODER_CHECK_STATUS(VA_STATUS_SUCCESS ==va_status,
366                        ENCODER_PICTURE_ERR,
367                        "mpeg4 rendering slice-parameters buffer failed.");
368
369   /*swap ref_surface and recon_surface */
370   GstVaapiSurface *swap = mpeg4_prv->ref_surface;
371   mpeg4_prv->ref_surface = mpeg4_prv->recon_surface;
372   mpeg4_prv->recon_surface = swap;
373
374 end:
375   return ret;
376 }
377
378 #if 0
379 static GstBuffer *
380 gst_mpeg4_encoder_copy_coded_buffer(GstVaapiBaseEncoder *encoder,
381             guint8 *frame, guint32 frame_size, VABufferID *coded_buf)
382
383 {
384    /*process data*/
385   GstBuffer* buffer = gst_buffer_new_and_alloc(frame_size);
386   memcpy(GST_BUFFER_DATA(buffer), frame, frame_size);
387
388   #if 0
389   GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
390   if (mpeg4_encoder->profile == VAProfileMPEG4AdvancedSimple) {
391     guint8 *start_code = GST_BUFFER_DATA(buffer)+16; /*fix old issue of ASP in mrst platform*/
392     if (start_code[0] == 0x01 && start_code[1] == 0x20
393         && start_code[-1] == 0x00 && start_code[-2] == 0x00)
394     {
395       start_code[2] = 0x08;
396     }
397   }
398   #endif
399
400   return buffer;
401 }
402 #endif
403
404 static void
405 gst_mpeg4_notify_frame(GstVaapiBaseEncoder *encoder, guint8 *buf, guint32 size)
406 {
407   GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(encoder);
408   if (!mpeg4_prv->codec_data) {
409     if (!mpeg4_encoder_generate_codec_data(buf, size, &mpeg4_prv->codec_data)) {
410       ENCODER_LOG_ERROR("mpeg4 encoder coded data error, please check <mpeg4_encoder_generate_codec_data>.");
411     }
412   }
413   if (mpeg4_prv->codec_data) {
414     gst_vaapi_base_encoder_set_frame_notify(GST_VAAPI_BASE_ENCODER(encoder), FALSE);
415   }
416 }
417
418
419 static EncoderStatus
420 gst_mpeg4_encoder_flush(GstVaapiEncoder* encoder, GstVaapiDisplay *display,
421                        GstVaapiContext *context, GList **coded_pics)
422 {
423   GstMPEG4Encoder *mpeg4_encoder = GST_MPEG4_ENCODER(encoder);
424
425   mpeg4_release_parameters(mpeg4_encoder, display);
426   return ENCODER_NO_ERROR;
427 }
428
429
430 static EncoderStatus
431 gst_mpeg4_encoder_get_codec_data(GstVaapiEncoder *encoder, GstBuffer **buffer)
432 {
433   GstMPEG4EncoderPrivate *mpeg4_prv = GST_MPEG4_ENCODER_GET_PRIVATE(encoder);
434
435   if (!mpeg4_prv->codec_data)
436     return ENCODER_DATA_NOT_READY;
437   *buffer = gst_buffer_ref(mpeg4_prv->codec_data);
438   return ENCODER_NO_ERROR;
439 }
440
441 #define VISUAL_OBJECT_SEQUENCE_START_CODE  0x000001B0
442 #define VISUAL_OBJECT_SEQUENCE_END_CODE    0x000001B1
443 #define VISUAL_OBJECT_START_CODE           0x000001B5
444 #define VIDEO_OBJECT_PLANE_START_CODE      0x000001B6
445 /* Video Object Start Code range */
446 #define VIDEO_OBJECT_START_CODE_MIN        0x00000100
447 #define VIDEO_OBJECT_START_CODE_MAX        0x0000011F
448 /* Video Object Layer Start Code range 0x00000120 ~ 0x0000012F*/
449 #define VIDEO_OBJECT_LAYER_START_CODE      0x00000120
450 #define VIDEO_OBJECT_LAYER_START_CODE_MASK 0xFFFFFFF0
451
452
453 static gboolean
454 find_video_object_configuration_info(const guint8 *in_buffer, guint32 in_size,
455                                      const guint8 **out_buffer, guint32 *out_size)
456 {
457   guint32 value = 0x00;
458   const guint8 *end = in_buffer + in_size;
459
460   while(in_buffer < end) {
461     value = ((value<<8)|(*in_buffer));
462     if (VISUAL_OBJECT_SEQUENCE_START_CODE == value) {
463       *out_buffer = in_buffer - 3;
464       ++in_buffer;
465       break;
466     }
467     ++in_buffer;
468   }
469   if (in_buffer >= end)
470     return FALSE;
471
472   while(in_buffer < end) {
473     value = ((value<<8)|(*in_buffer));
474     if (VIDEO_OBJECT_PLANE_START_CODE == value) {
475       *out_size = (in_buffer - 3 - *out_buffer);
476       return TRUE;
477     }
478     ++in_buffer;
479   }
480   return FALSE;
481 }
482
483 static gboolean
484 mpeg4_encoder_generate_codec_data(const guint8 *in_buffer, guint32 in_size, GstBuffer **out_buffer)
485 {
486   const guint8 *codec_buffer = NULL;
487   guint32 codec_size = 0;
488   guint8 *visual_obj_seq_end = NULL;
489
490   if (!find_video_object_configuration_info(in_buffer, in_size, &codec_buffer, &codec_size)) {
491     return FALSE;
492   }
493   ENCODER_ASSERT(codec_size);
494   *out_buffer = gst_buffer_new_and_alloc(codec_size+4);
495   memcpy(GST_BUFFER_DATA(*out_buffer), codec_buffer, codec_size);
496   visual_obj_seq_end = GST_BUFFER_DATA(*out_buffer) + codec_size;
497   visual_obj_seq_end[0] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>24);
498   visual_obj_seq_end[1] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>16);
499   visual_obj_seq_end[2] = (VISUAL_OBJECT_SEQUENCE_END_CODE>>8);
500   visual_obj_seq_end[3] = (guint8)VISUAL_OBJECT_SEQUENCE_END_CODE;
501   return TRUE;
502 }
503