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