• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright (C) 2015 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************
18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20 
21 /**
22 ******************************************************************************
23 * @file
24 *  ih264e_encode.c
25 *
26 * @brief
27 *  This file contains functions for encoding the input yuv frame in synchronous
28 *  api mode
29 *
30 * @author
31 *  ittiam
32 *
33 * List of Functions
34 *  - ih264e_join_threads()
35 *  - ih264e_wait_for_thread()
36 *  - ih264e_encode()
37 *
38 ******************************************************************************
39 */
40 
41 /*****************************************************************************/
42 /* File Includes                                                             */
43 /*****************************************************************************/
44 
45 /* System Include files */
46 #include <stdio.h>
47 #include <stddef.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <assert.h>
51 #include <limits.h>
52 /* User Include files */
53 #include "ih264e_config.h"
54 #include "ih264_typedefs.h"
55 #include "iv2.h"
56 #include "ive2.h"
57 #include "ih264e.h"
58 #include "ithread.h"
59 #include "ih264_defs.h"
60 #include "ih264_macros.h"
61 #include "ih264_debug.h"
62 #include "ih264_structs.h"
63 #include "ih264_platform_macros.h"
64 #include "ih264_error.h"
65 #include "ime_distortion_metrics.h"
66 #include "ime_defs.h"
67 #include "ime_structs.h"
68 #include "ih264_trans_quant_itrans_iquant.h"
69 #include "ih264_inter_pred_filters.h"
70 #include "ih264_mem_fns.h"
71 #include "ih264_padding.h"
72 #include "ih264_intra_pred_filters.h"
73 #include "ih264_deblk_edge_filters.h"
74 #include "ih264_cabac_tables.h"
75 #include "ih264_list.h"
76 #include "ih264e_error.h"
77 #include "ih264e_defs.h"
78 #include "ih264e_bitstream.h"
79 #include "irc_mem_req_and_acq.h"
80 #include "irc_cntrl_param.h"
81 #include "irc_frame_info_collector.h"
82 #include "ih264e_rate_control.h"
83 #include "ih264e_time_stamp.h"
84 #include "ih264e_cabac_structs.h"
85 #include "ih264e_structs.h"
86 #include "ih264e_master.h"
87 #include "ih264e_process.h"
88 #include "ih264_buf_mgr.h"
89 #include "ih264_dpb_mgr.h"
90 #include "ih264e_utils.h"
91 #include "ih264e_fmt_conv.h"
92 #include "ih264e_statistics.h"
93 #include "ih264e_trace.h"
94 #include "ih264e_debug.h"
95 #ifdef LOGO_EN
96 #include "ih264e_ittiam_logo.h"
97 #endif
98 
99 
100 #define SEI_BASED_FORCE_IDR 1
101 
102 /*****************************************************************************/
103 /* Function Definitions                                                      */
104 /*****************************************************************************/
105 
106 /**
107 ******************************************************************************
108 *
109 * @brief
110 *  This function joins all the spawned threads after successful completion of
111 *  their tasks
112 *
113 * @par   Description
114 *
115 * @param[in] ps_codec
116 *  pointer to codec context
117 *
118 * @returns  none
119 *
120 ******************************************************************************
121 */
ih264e_join_threads(codec_t * ps_codec)122 void ih264e_join_threads(codec_t *ps_codec)
123 {
124     /* temp var */
125    WORD32 i = 0;
126    WORD32 ret = 0;
127 
128    /* join spawned threads */
129    while (i < ps_codec->i4_proc_thread_cnt)
130    {
131        if (ps_codec->ai4_process_thread_created[i])
132        {
133            ret = ithread_join(ps_codec->apv_proc_thread_handle[i], NULL);
134            if (ret != 0)
135            {
136                printf("pthread Join Failed");
137                assert(0);
138            }
139            ps_codec->ai4_process_thread_created[i] = 0;
140            i++;
141        }
142    }
143 
144    ps_codec->i4_proc_thread_cnt = 0;
145 }
146 
147 /**
148 ******************************************************************************
149 *
150 * @brief This function puts the current thread to sleep for a duration
151 *  of sleep_us
152 *
153 * @par Description
154 *  ithread_yield() method causes the calling thread to yield execution to another
155 *  thread that is ready to run on the current processor. The operating system
156 *  selects the thread to yield to. ithread_usleep blocks the current thread for
157 *  the specified number of milliseconds. In other words, yield just says,
158 *  end my timeslice prematurely, look around for other threads to run. If there
159 *  is nothing better than me, continue. Sleep says I don't want to run for x
160 *  milliseconds. Even if no other thread wants to run, don't make me run.
161 *
162 * @param[in] sleep_us
163 *  thread sleep duration
164 *
165 * @returns error_status
166 *
167 ******************************************************************************
168 */
ih264e_wait_for_thread(UWORD32 sleep_us)169 IH264E_ERROR_T ih264e_wait_for_thread(UWORD32 sleep_us)
170 {
171     /* yield thread */
172     ithread_yield();
173 
174     /* put thread to sleep */
175     ithread_usleep(sleep_us);
176 
177     return IH264E_SUCCESS;
178 }
179 
180 /**
181 ******************************************************************************
182 *
183 * @brief
184 *  Encodes in synchronous api mode
185 *
186 * @par Description
187 *  This routine processes input yuv, encodes it and outputs bitstream and recon
188 *
189 * @param[in] ps_codec_obj
190 *  Pointer to codec object at API level
191 *
192 * @param[in] pv_api_ip
193 *  Pointer to input argument structure
194 *
195 * @param[out] pv_api_op
196 *  Pointer to output argument structure
197 *
198 * @returns  Status
199 *
200 ******************************************************************************
201 */
ih264e_encode(iv_obj_t * ps_codec_obj,void * pv_api_ip,void * pv_api_op)202 WORD32 ih264e_encode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
203 {
204     /* error status */
205     IH264E_ERROR_T error_status = IH264E_SUCCESS;
206 
207     /* codec ctxt */
208     codec_t *ps_codec = (codec_t *)ps_codec_obj->pv_codec_handle;
209 
210     /* input frame to encode */
211     ih264e_video_encode_ip_t *ps_video_encode_ip = pv_api_ip;
212 
213     /* output buffer to write stream */
214     ih264e_video_encode_op_t *ps_video_encode_op = pv_api_op;
215 
216     /* i/o structures */
217     inp_buf_t s_inp_buf;
218     out_buf_t s_out_buf;
219 
220     /* temp var */
221     WORD32 ctxt_sel = 0, i, i4_rc_pre_enc_skip;
222 
223     /********************************************************************/
224     /*                            BEGIN INIT                            */
225     /********************************************************************/
226     /* reset output structure */
227     ps_video_encode_op->s_ive_op.u4_error_code = IV_SUCCESS;
228     ps_video_encode_op->s_ive_op.output_present  = 0;
229     ps_video_encode_op->s_ive_op.dump_recon = 0;
230     ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_NA_FRAME;
231     /* By default set the current input buffer as the buffer to be freed */
232     /* This will later be updated to the actual input that gets encoded */
233     ps_video_encode_op->s_ive_op.s_inp_buf = ps_video_encode_ip->s_ive_ip.s_inp_buf;
234 
235     /* Check for output memory allocation size */
236     if (ps_video_encode_ip->s_ive_ip.s_out_buf.u4_bufsize < MIN_STREAM_SIZE)
237     {
238         error_status = IH264E_INSUFFICIENT_OUTPUT_BUFFER;
239         SET_ERROR_ON_RETURN(error_status,
240                             IVE_UNSUPPORTEDPARAM,
241                             ps_video_encode_op->s_ive_op.u4_error_code,
242                             IV_FAIL);
243     }
244 
245     /* copy output info. to internal structure */
246     s_out_buf.s_bits_buf = ps_video_encode_ip->s_ive_ip.s_out_buf;
247     s_out_buf.u4_is_last = 0;
248     s_out_buf.u4_timestamp_low = ps_video_encode_ip->s_ive_ip.u4_timestamp_low;
249     s_out_buf.u4_timestamp_high = ps_video_encode_ip->s_ive_ip.u4_timestamp_high;
250 
251     /* api call cnt */
252     ps_codec->i4_encode_api_call_cnt += 1;
253 
254     /* codec context selector */
255     ctxt_sel = ps_codec->i4_encode_api_call_cnt % MAX_CTXT_SETS;
256 
257     /* reset status flags */
258     ps_codec->ai4_pic_cnt[ctxt_sel] = -1;
259     ps_codec->s_rate_control.post_encode_skip[ctxt_sel] = 0;
260     ps_codec->s_rate_control.pre_encode_skip[ctxt_sel] = 0;
261 
262     /* pass output buffer to codec */
263     ps_codec->as_out_buf[ctxt_sel] = s_out_buf;
264 
265     /* initialize codec ctxt with default params for the first encode api call */
266     if (ps_codec->i4_encode_api_call_cnt == 0)
267     {
268         ih264e_codec_init(ps_codec);
269     }
270 
271     /* parse configuration params */
272     for (i = 0; i < MAX_ACTIVE_CONFIG_PARAMS; i++)
273     {
274         cfg_params_t *ps_cfg = &ps_codec->as_cfg[i];
275 
276         if (1 == ps_cfg->u4_is_valid)
277         {
278             if ( ((ps_cfg->u4_timestamp_high == ps_video_encode_ip->s_ive_ip.u4_timestamp_high) &&
279                             (ps_cfg->u4_timestamp_low == ps_video_encode_ip->s_ive_ip.u4_timestamp_low)) ||
280                             ((WORD32)ps_cfg->u4_timestamp_high == -1) ||
281                             ((WORD32)ps_cfg->u4_timestamp_low == -1) )
282             {
283                 error_status = ih264e_codec_update_config(ps_codec, ps_cfg);
284                 SET_ERROR_ON_RETURN(error_status,
285                                     IVE_UNSUPPORTEDPARAM,
286                                     ps_video_encode_op->s_ive_op.u4_error_code,
287                                     IV_FAIL);
288 
289                 ps_cfg->u4_is_valid = 0;
290             }
291         }
292     }
293     /* Force IDR based on SEI params */
294 #if SEI_BASED_FORCE_IDR
295     {
296         sei_mdcv_params_t *ps_sei_mdcv_params = &ps_codec->s_sei.s_sei_mdcv_params;
297         sei_mdcv_params_t *ps_cfg_sei_mdcv_params =
298                                 &ps_codec->s_cfg.s_sei.s_sei_mdcv_params;
299         sei_cll_params_t *ps_sei_cll_params = &ps_codec->s_sei.s_sei_cll_params;
300         sei_cll_params_t *ps_cfg_sei_cll_params =
301                                 &ps_codec->s_cfg.s_sei.s_sei_cll_params;
302         sei_ave_params_t *ps_sei_ave_params = &ps_codec->s_sei.s_sei_ave_params;
303         sei_ave_params_t *ps_cfg_sei_ave_params =
304                                 &ps_codec->s_cfg.s_sei.s_sei_ave_params;
305 
306         if((ps_sei_mdcv_params->au2_display_primaries_x[0]!=
307                                 ps_cfg_sei_mdcv_params->au2_display_primaries_x[0]) ||
308             (ps_sei_mdcv_params->au2_display_primaries_x[1] !=
309                                 ps_cfg_sei_mdcv_params->au2_display_primaries_x[1]) ||
310             (ps_sei_mdcv_params->au2_display_primaries_x[2] !=
311                                 ps_cfg_sei_mdcv_params->au2_display_primaries_x[2]) ||
312             (ps_sei_mdcv_params->au2_display_primaries_y[0] !=
313                                 ps_cfg_sei_mdcv_params->au2_display_primaries_y[0]) ||
314             (ps_sei_mdcv_params->au2_display_primaries_y[1] !=
315                                 ps_cfg_sei_mdcv_params->au2_display_primaries_y[1]) ||
316             (ps_sei_mdcv_params->au2_display_primaries_y[2] !=
317                                 ps_cfg_sei_mdcv_params->au2_display_primaries_y[2]) ||
318             (ps_sei_mdcv_params->u2_white_point_x !=
319                                 ps_cfg_sei_mdcv_params->u2_white_point_x) ||
320             (ps_sei_mdcv_params->u2_white_point_y !=
321                                 ps_cfg_sei_mdcv_params->u2_white_point_y) ||
322             (ps_sei_mdcv_params->u4_max_display_mastering_luminance !=
323                                 ps_cfg_sei_mdcv_params->u4_max_display_mastering_luminance) ||
324             (ps_sei_mdcv_params->u4_min_display_mastering_luminance !=
325                                 ps_cfg_sei_mdcv_params->u4_min_display_mastering_luminance))
326         {
327             ps_codec->s_sei.s_sei_mdcv_params = ps_codec->s_cfg.s_sei.s_sei_mdcv_params;
328             ps_codec->s_sei.u1_sei_mdcv_params_present_flag = 1;
329         }
330         else
331         {
332             ps_codec->s_sei.u1_sei_mdcv_params_present_flag = 0;
333         }
334 
335         if((ps_sei_cll_params->u2_max_content_light_level !=
336                                 ps_cfg_sei_cll_params->u2_max_content_light_level) ||
337                 (ps_sei_cll_params->u2_max_pic_average_light_level !=
338                                 ps_cfg_sei_cll_params->u2_max_pic_average_light_level))
339         {
340             ps_codec->s_sei.s_sei_cll_params = ps_codec->s_cfg.s_sei.s_sei_cll_params;
341             ps_codec->s_sei.u1_sei_cll_params_present_flag = 1;
342         }
343         else
344         {
345             ps_codec->s_sei.u1_sei_cll_params_present_flag = 0;
346         }
347 
348         if((ps_sei_ave_params->u4_ambient_illuminance !=
349                                 ps_cfg_sei_ave_params->u4_ambient_illuminance) ||
350                 (ps_sei_ave_params->u2_ambient_light_x !=
351                                 ps_cfg_sei_ave_params->u2_ambient_light_x) ||
352                 (ps_sei_ave_params->u2_ambient_light_y !=
353                                 ps_cfg_sei_ave_params->u2_ambient_light_y))
354         {
355             ps_codec->s_sei.s_sei_ave_params = ps_codec->s_cfg.s_sei.s_sei_ave_params;
356             ps_codec->s_sei.u1_sei_ave_params_present_flag = 1;
357         }
358         else
359         {
360             ps_codec->s_sei.u1_sei_ave_params_present_flag = 0;
361         }
362 
363         if((1 == ps_codec->s_sei.u1_sei_mdcv_params_present_flag) ||
364                 (1 == ps_codec->s_sei.u1_sei_cll_params_present_flag) ||
365                 (1 == ps_codec->s_sei.u1_sei_ave_params_present_flag))
366         {
367             ps_codec->force_curr_frame_type = IV_IDR_FRAME;
368         }
369     }
370 #endif
371     /******************************************************************
372      * INSERT LOGO
373      *****************************************************************/
374 #ifdef LOGO_EN
375     if (s_inp_buf.s_raw_buf.apv_bufs[0] != NULL &&
376                     ps_codec->i4_header_mode != 1)
377     {
378         ih264e_insert_logo(s_inp_buf.s_raw_buf.apv_bufs[0],
379                            s_inp_buf.s_raw_buf.apv_bufs[1],
380                            s_inp_buf.s_raw_buf.apv_bufs[2],
381                            s_inp_buf.s_raw_buf.au4_strd[0],
382                            0,
383                            0,
384                            ps_codec->s_cfg.e_inp_color_fmt,
385                            ps_codec->s_cfg.u4_disp_wd,
386                            ps_codec->s_cfg.u4_disp_ht);
387     }
388 #endif /*LOGO_EN*/
389 
390     /* In case of alt ref and B pics we will have non reference frame in stream */
391     if (ps_codec->s_cfg.u4_enable_alt_ref || ps_codec->s_cfg.u4_num_bframes)
392     {
393         ps_codec->i4_non_ref_frames_in_stream = 1;
394     }
395 
396     if (ps_codec->i4_encode_api_call_cnt == 0)
397     {
398         /********************************************************************/
399         /*   number of mv/ref bank buffers used by the codec,               */
400         /*      1 to handle curr frame                                      */
401         /*      1 to store information of ref frame                         */
402         /*      1 more additional because of the codec employs 2 ctxt sets  */
403         /*        to assist asynchronous API                                */
404         /********************************************************************/
405 
406         /* initialize mv bank buffer manager */
407         error_status = ih264e_mv_buf_mgr_add_bufs(ps_codec);
408         SET_ERROR_ON_RETURN(error_status,
409                             IVE_FATALERROR,
410                             ps_video_encode_op->s_ive_op.u4_error_code,
411                             IV_FAIL);
412 
413         /* initialize ref bank buffer manager */
414         error_status = ih264e_pic_buf_mgr_add_bufs(ps_codec);
415         SET_ERROR_ON_RETURN(error_status,
416                             IVE_FATALERROR,
417                             ps_video_encode_op->s_ive_op.u4_error_code,
418                             IV_FAIL);
419 
420         /* for the first frame, generate header when not requested explicitly */
421         if (ps_codec->i4_header_mode == 0 &&
422                         ps_codec->u4_header_generated == 0)
423         {
424             ps_codec->i4_gen_header = 1;
425         }
426     }
427 
428     /* generate header and return when encoder is operated in header mode */
429     if (ps_codec->i4_header_mode == 1)
430     {
431         /* whenever the header is generated, this implies a start of sequence
432          * and a sequence needs to be started with IDR
433          */
434         ps_codec->force_curr_frame_type = IV_IDR_FRAME;
435 
436         /* generate header */
437         error_status = ih264e_generate_sps_pps(ps_codec);
438 
439         /* send the input to app */
440         ps_video_encode_op->s_ive_op.s_inp_buf = ps_video_encode_ip->s_ive_ip.s_inp_buf;
441         ps_video_encode_op->s_ive_op.u4_timestamp_low = ps_video_encode_ip->s_ive_ip.u4_timestamp_low;
442         ps_video_encode_op->s_ive_op.u4_timestamp_high = ps_video_encode_ip->s_ive_ip.u4_timestamp_high;
443 
444         ps_video_encode_op->s_ive_op.u4_is_last = ps_video_encode_ip->s_ive_ip.u4_is_last;
445 
446         /* send the output to app */
447         ps_video_encode_op->s_ive_op.output_present  = 1;
448         ps_video_encode_op->s_ive_op.dump_recon = 0;
449         ps_video_encode_op->s_ive_op.s_out_buf = ps_codec->as_out_buf[ctxt_sel].s_bits_buf;
450 
451         /* error status */
452         SET_ERROR_ON_RETURN(error_status,
453                             IVE_FATALERROR,
454                             ps_video_encode_op->s_ive_op.u4_error_code,
455                             IV_FAIL);
456 
457         /* indicates that header has been generated previously */
458         ps_codec->u4_header_generated = 1;
459 
460         /* api call cnt */
461         ps_codec->i4_encode_api_call_cnt --;
462 
463         /* header mode tag is not sticky */
464         ps_codec->i4_header_mode = 0;
465         ps_codec->i4_gen_header = 0;
466 
467         return IV_SUCCESS;
468     }
469 
470     /* curr pic cnt */
471      ps_codec->i4_pic_cnt += 1;
472 
473     i4_rc_pre_enc_skip = 0;
474     i4_rc_pre_enc_skip = ih264e_input_queue_update(
475                     ps_codec, &ps_video_encode_ip->s_ive_ip, &s_inp_buf);
476 
477     s_out_buf.u4_is_last = s_inp_buf.u4_is_last;
478     ps_video_encode_op->s_ive_op.u4_is_last = s_inp_buf.u4_is_last;
479 
480     /* Send the input to application so that it can free it */
481     ps_video_encode_op->s_ive_op.s_inp_buf = s_inp_buf.s_raw_buf;
482 
483     /* Only encode if the current frame is not pre-encode skip */
484     if (!i4_rc_pre_enc_skip && s_inp_buf.s_raw_buf.apv_bufs[0])
485     {
486         /* proc ctxt base idx */
487         WORD32 proc_ctxt_select = ctxt_sel * MAX_PROCESS_THREADS;
488 
489         /* proc ctxt */
490         process_ctxt_t *ps_proc = &ps_codec->as_process[proc_ctxt_select];
491 
492         WORD32 ret = 0;
493 
494         /* number of addl. threads to be created */
495         WORD32 num_thread_cnt = ps_codec->s_cfg.u4_num_cores - 1;
496 
497         /* array giving pic cnt that is being processed in curr context set */
498         ps_codec->ai4_pic_cnt[ctxt_sel] = ps_codec->i4_pic_cnt;
499 
500         /* initialize all relevant process ctxts */
501         error_status = ih264e_pic_init(ps_codec, &s_inp_buf);
502         SET_ERROR_ON_RETURN(error_status,
503                             IVE_FATALERROR,
504                             ps_video_encode_op->s_ive_op.u4_error_code,
505                             IV_FAIL);
506 
507         for (i = 0; i < num_thread_cnt; i++)
508         {
509             ret = ithread_create(ps_codec->apv_proc_thread_handle[i],
510                                  NULL,
511                                  (void *)ih264e_process_thread,
512                                  &ps_codec->as_process[i + 1]);
513             if (ret != 0)
514             {
515                 printf("pthread Create Failed");
516                 assert(0);
517             }
518 
519             ps_codec->ai4_process_thread_created[i] = 1;
520 
521             ps_codec->i4_proc_thread_cnt++;
522         }
523 
524 
525         /* launch job */
526         ih264e_process_thread(ps_proc);
527 
528         /* Join threads at the end of encoding a frame */
529         ih264e_join_threads(ps_codec);
530 
531         ih264_list_reset(ps_codec->pv_proc_jobq);
532 
533         ih264_list_reset(ps_codec->pv_entropy_jobq);
534     }
535 
536 
537    /****************************************************************************
538    * RECON
539    *    Since we have forward dependent frames, we cannot return recon in encoding
540    *    order. It must be in poc order, or input pic order. To achieve this we
541    *    introduce a delay of 1 to the recon wrt encode. Now since we have that
542    *    delay, at any point minimum of pic_cnt in our ref buffer will be the
543    *    correct frame. For ex let our GOP be IBBP [1 2 3 4] . The encode order
544    *    will be [1 4 2 3] .Now since we have a delay of 1, when we are done with
545    *    encoding 4, the min in the list will be 1. After encoding 2, it will be
546    *    2, 3 after 3 and 4 after 4. Hence we can return in sequence. Note
547    *    that the 1 delay is critical. Hence if we have post enc skip, we must
548    *    skip here too. Note that since post enc skip already frees the recon
549    *    buffer we need not do any thing here
550    *
551    *    We need to return a recon when ever we consume an input buffer. This
552    *    comsumption include a pre or post enc skip. Thus dump recon is set for
553    *    all cases except when
554    *    1) We are waiting -> ps_codec->i4_pic_cnt > ps_codec->s_cfg.u4_num_bframe
555    *        An exception need to be made for the case when we have the last buffer
556    *        since we need to flush out the on remainig recon.
557    ****************************************************************************/
558 
559     ps_video_encode_op->s_ive_op.dump_recon = 0;
560 
561     if (ps_codec->s_cfg.u4_enable_recon
562                     && (ps_codec->i4_pic_cnt > (WORD32)ps_codec->s_cfg.u4_num_bframes ||
563                         s_inp_buf.u4_is_last))
564     {
565         /* error status */
566         IH264_ERROR_T ret = IH264_SUCCESS;
567         pic_buf_t *ps_pic_buf = NULL;
568         WORD32 i4_buf_status, i4_curr_poc = 32768;
569 
570         /* In case of skips we return recon, but indicate that buffer is zero size */
571         if (ps_codec->s_rate_control.post_encode_skip[ctxt_sel]
572                         || i4_rc_pre_enc_skip)
573         {
574 
575             ps_video_encode_op->s_ive_op.dump_recon = 1;
576             ps_video_encode_op->s_ive_op.s_recon_buf.au4_wd[0] = 0;
577             ps_video_encode_op->s_ive_op.s_recon_buf.au4_wd[1] = 0;
578 
579         }
580         else
581         {
582             for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
583             {
584                 if (ps_codec->as_ref_set[i].i4_pic_cnt == -1)
585                     continue;
586 
587                 i4_buf_status = ih264_buf_mgr_get_status(
588                                 ps_codec->pv_ref_buf_mgr,
589                                 ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id);
590 
591                 if ((i4_buf_status & BUF_MGR_IO)
592                                 && (ps_codec->as_ref_set[i].i4_poc < i4_curr_poc))
593                 {
594                     ps_pic_buf = ps_codec->as_ref_set[i].ps_pic_buf;
595                     i4_curr_poc = ps_codec->as_ref_set[i].i4_poc;
596                 }
597             }
598 
599             ps_video_encode_op->s_ive_op.s_recon_buf =
600                             ps_video_encode_ip->s_ive_ip.s_recon_buf;
601 
602             /*
603              * If we get a valid buffer. output and free recon.
604              *
605              * we may get an invalid buffer if num_b_frames is 0. This is because
606              * We assume that there will be a ref frame in ref list after encoding
607              * the last frame. With B frames this is correct since its forward ref
608              * pic will be in the ref list. But if num_b_frames is 0, we will not
609              * have a forward ref pic
610              */
611 
612             if (ps_pic_buf)
613             {
614                 /* copy/convert the recon buffer and return */
615                 ih264e_fmt_conv(ps_codec,
616                                 ps_pic_buf,
617                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.apv_bufs[0],
618                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.apv_bufs[1],
619                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.apv_bufs[2],
620                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.au4_wd[0],
621                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.au4_wd[1],
622                                 0, ps_codec->s_cfg.u4_disp_ht);
623 
624                 ps_video_encode_op->s_ive_op.dump_recon = 1;
625 
626                 ret = ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr,
627                                             ps_pic_buf->i4_buf_id, BUF_MGR_IO);
628 
629                 if (IH264_SUCCESS != ret)
630                 {
631                     SET_ERROR_ON_RETURN(
632                                     (IH264E_ERROR_T)ret, IVE_FATALERROR,
633                                     ps_video_encode_op->s_ive_op.u4_error_code,
634                                     IV_FAIL);
635                 }
636             }
637         }
638     }
639 
640 
641     /***************************************************************************
642      * Free reference buffers:
643      * In case of a post enc skip, we have to ensure that those pics will not
644      * be used as reference anymore. In all other cases we will not even mark
645      * the ref buffers
646      ***************************************************************************/
647     if (ps_codec->s_rate_control.post_encode_skip[ctxt_sel])
648     {
649         /* pic info */
650         pic_buf_t *ps_cur_pic;
651 
652         /* mv info */
653         mv_buf_t *ps_cur_mv_buf;
654 
655         /* error status */
656         IH264_ERROR_T ret = IH264_SUCCESS;
657 
658         /* Decrement coded pic count */
659         ps_codec->i4_poc--;
660 
661         /* loop through to get the min pic cnt among the list of pics stored in ref list */
662         /* since the skipped frame may not be on reference list, we may not have an MV bank
663          * hence free only if we have allocated */
664         for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
665         {
666             if (ps_codec->i4_pic_cnt == ps_codec->as_ref_set[i].i4_pic_cnt)
667             {
668 
669                 ps_cur_pic = ps_codec->as_ref_set[i].ps_pic_buf;
670 
671                 ps_cur_mv_buf = ps_codec->as_ref_set[i].ps_mv_buf;
672 
673                 /* release this frame from reference list and recon list */
674                 ret = ih264_buf_mgr_release(ps_codec->pv_mv_buf_mgr, ps_cur_mv_buf->i4_buf_id , BUF_MGR_REF);
675                 ret |= ih264_buf_mgr_release(ps_codec->pv_mv_buf_mgr, ps_cur_mv_buf->i4_buf_id , BUF_MGR_IO);
676                 SET_ERROR_ON_RETURN((IH264E_ERROR_T)ret,
677                                     IVE_FATALERROR,
678                                     ps_video_encode_op->s_ive_op.u4_error_code,
679                                     IV_FAIL);
680 
681                 ret = ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr, ps_cur_pic->i4_buf_id , BUF_MGR_REF);
682                 ret |= ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr, ps_cur_pic->i4_buf_id , BUF_MGR_IO);
683                 SET_ERROR_ON_RETURN((IH264E_ERROR_T)ret,
684                                     IVE_FATALERROR,
685                                     ps_video_encode_op->s_ive_op.u4_error_code,
686                                     IV_FAIL);
687                 break;
688             }
689         }
690     }
691 
692     /*
693      * Since recon is not in sync with output, ie there can be frame to be
694      * given back as recon even after last output. Hence we need to mark that
695      * the output is not the last.
696      * Hence search through reflist and mark appropriately
697      */
698     if (ps_codec->s_cfg.u4_enable_recon)
699     {
700         WORD32 i4_buf_status = 0;
701 
702         for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
703         {
704             if (ps_codec->as_ref_set[i].i4_pic_cnt == -1)
705                 continue;
706 
707             i4_buf_status |= ih264_buf_mgr_get_status(
708                             ps_codec->pv_ref_buf_mgr,
709                             ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id);
710         }
711 
712         if (i4_buf_status & BUF_MGR_IO)
713         {
714             s_out_buf.u4_is_last = 0;
715             ps_video_encode_op->s_ive_op.u4_is_last = 0;
716         }
717     }
718 
719 
720     /**************************************************************************
721      * Signaling to APP
722      *  1) If we valid a valid output mark it so
723      *  2) Set the codec output ps_video_encode_op
724      *  3) Set the error status
725      *  4) Set the return Pic type
726      *      Note that we already has marked recon properly
727      *  5)Send the consumed input back to app so that it can free it if possible
728      *
729      *  We will have to return the output and input buffers unconditionally
730      *  so that app can release them
731      **************************************************************************/
732     if (!i4_rc_pre_enc_skip
733                     && !ps_codec->s_rate_control.post_encode_skip[ctxt_sel]
734                     && s_inp_buf.s_raw_buf.apv_bufs[0])
735     {
736 
737         /* receive output back from codec */
738         s_out_buf = ps_codec->as_out_buf[ctxt_sel];
739 
740         /* send the output to app */
741         ps_video_encode_op->s_ive_op.output_present  = 1;
742         ps_video_encode_op->s_ive_op.u4_error_code = IV_SUCCESS;
743 
744         /* Set the time stamps of the encodec input */
745         ps_video_encode_op->s_ive_op.u4_timestamp_low = s_inp_buf.u4_timestamp_low;
746         ps_video_encode_op->s_ive_op.u4_timestamp_high = s_inp_buf.u4_timestamp_high;
747 
748 
749         switch (ps_codec->pic_type)
750         {
751             case PIC_IDR:
752                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type =IV_IDR_FRAME;
753                 break;
754 
755             case PIC_I:
756                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_I_FRAME;
757                 break;
758 
759             case PIC_P:
760                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_P_FRAME;
761                 break;
762 
763             case PIC_B:
764                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_B_FRAME;
765                 break;
766 
767             default:
768                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_NA_FRAME;
769                 break;
770         }
771 
772         for (i = 0; i < (WORD32)ps_codec->s_cfg.u4_num_cores; i++)
773         {
774             error_status = ps_codec->as_process[ctxt_sel + i].i4_error_code;
775             SET_ERROR_ON_RETURN(error_status,
776                                 IVE_FATALERROR,
777                                 ps_video_encode_op->s_ive_op.u4_error_code,
778                                 IV_FAIL);
779         }
780     }
781     else
782     {
783         /* receive output back from codec */
784         s_out_buf = ps_codec->as_out_buf[ctxt_sel];
785 
786         ps_video_encode_op->s_ive_op.output_present = 0;
787         ps_video_encode_op->s_ive_op.u4_error_code = IV_SUCCESS;
788 
789         /* Set the time stamps of the encodec input */
790         ps_video_encode_op->s_ive_op.u4_timestamp_low = 0;
791         ps_video_encode_op->s_ive_op.u4_timestamp_high = 0;
792 
793         ps_video_encode_op->s_ive_op.u4_encoded_frame_type =  IV_NA_FRAME;
794 
795     }
796 
797     ps_video_encode_op->s_ive_op.s_out_buf = s_out_buf.s_bits_buf;
798 
799     if (1 == s_inp_buf.u4_is_last)
800     {
801         ps_video_encode_op->s_ive_op.output_present = 0;
802         ps_video_encode_op->s_ive_op.dump_recon = 0;
803     }
804 
805     return IV_SUCCESS;
806 }
807