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 /* Function Definitions                                                      */
101 /*****************************************************************************/
102 
103 /**
104 ******************************************************************************
105 *
106 * @brief
107 *  This function joins all the spawned threads after successful completion of
108 *  their tasks
109 *
110 * @par   Description
111 *
112 * @param[in] ps_codec
113 *  pointer to codec context
114 *
115 * @returns  none
116 *
117 ******************************************************************************
118 */
ih264e_join_threads(codec_t * ps_codec)119 void ih264e_join_threads(codec_t *ps_codec)
120 {
121     /* temp var */
122    WORD32 i = 0;
123    WORD32 ret = 0;
124 
125    /* join spawned threads */
126    while (i < ps_codec->i4_proc_thread_cnt)
127    {
128        if (ps_codec->ai4_process_thread_created[i])
129        {
130            ret = ithread_join(ps_codec->apv_proc_thread_handle[i], NULL);
131            if (ret != 0)
132            {
133                printf("pthread Join Failed");
134                assert(0);
135            }
136            ps_codec->ai4_process_thread_created[i] = 0;
137            i++;
138        }
139    }
140 
141    ps_codec->i4_proc_thread_cnt = 0;
142 }
143 
144 /**
145 ******************************************************************************
146 *
147 * @brief This function puts the current thread to sleep for a duration
148 *  of sleep_us
149 *
150 * @par Description
151 *  ithread_yield() method causes the calling thread to yield execution to another
152 *  thread that is ready to run on the current processor. The operating system
153 *  selects the thread to yield to. ithread_usleep blocks the current thread for
154 *  the specified number of milliseconds. In other words, yield just says,
155 *  end my timeslice prematurely, look around for other threads to run. If there
156 *  is nothing better than me, continue. Sleep says I don't want to run for x
157 *  milliseconds. Even if no other thread wants to run, don't make me run.
158 *
159 * @param[in] sleep_us
160 *  thread sleep duration
161 *
162 * @returns error_status
163 *
164 ******************************************************************************
165 */
ih264e_wait_for_thread(UWORD32 sleep_us)166 IH264E_ERROR_T ih264e_wait_for_thread(UWORD32 sleep_us)
167 {
168     /* yield thread */
169     ithread_yield();
170 
171     /* put thread to sleep */
172     ithread_usleep(sleep_us);
173 
174     return IH264E_SUCCESS;
175 }
176 
177 /**
178 ******************************************************************************
179 *
180 * @brief
181 *  Encodes in synchronous api mode
182 *
183 * @par Description
184 *  This routine processes input yuv, encodes it and outputs bitstream and recon
185 *
186 * @param[in] ps_codec_obj
187 *  Pointer to codec object at API level
188 *
189 * @param[in] pv_api_ip
190 *  Pointer to input argument structure
191 *
192 * @param[out] pv_api_op
193 *  Pointer to output argument structure
194 *
195 * @returns  Status
196 *
197 ******************************************************************************
198 */
ih264e_encode(iv_obj_t * ps_codec_obj,void * pv_api_ip,void * pv_api_op)199 WORD32 ih264e_encode(iv_obj_t *ps_codec_obj, void *pv_api_ip, void *pv_api_op)
200 {
201     /* error status */
202     IH264E_ERROR_T error_status = IH264E_SUCCESS;
203 
204     /* codec ctxt */
205     codec_t *ps_codec = (codec_t *)ps_codec_obj->pv_codec_handle;
206 
207     /* input frame to encode */
208     ih264e_video_encode_ip_t *ps_video_encode_ip = pv_api_ip;
209 
210     /* output buffer to write stream */
211     ih264e_video_encode_op_t *ps_video_encode_op = pv_api_op;
212 
213     /* i/o structures */
214     inp_buf_t s_inp_buf;
215     out_buf_t s_out_buf;
216 
217     /* temp var */
218     WORD32 ctxt_sel = 0, i, i4_rc_pre_enc_skip;
219 
220     /********************************************************************/
221     /*                            BEGIN INIT                            */
222     /********************************************************************/
223     /* reset output structure */
224     ps_video_encode_op->s_ive_op.u4_error_code = IV_SUCCESS;
225     ps_video_encode_op->s_ive_op.output_present  = 0;
226     ps_video_encode_op->s_ive_op.dump_recon = 0;
227     ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_NA_FRAME;
228 
229     /* Check for output memory allocation size */
230     if (ps_video_encode_ip->s_ive_ip.s_out_buf.u4_bufsize < MIN_STREAM_SIZE)
231     {
232         error_status |= IH264E_INSUFFICIENT_OUTPUT_BUFFER;
233         SET_ERROR_ON_RETURN(error_status,
234                             IVE_UNSUPPORTEDPARAM,
235                             ps_video_encode_op->s_ive_op.u4_error_code,
236                             IV_FAIL);
237     }
238 
239     /* copy output info. to internal structure */
240     s_out_buf.s_bits_buf = ps_video_encode_ip->s_ive_ip.s_out_buf;
241     s_out_buf.u4_is_last = 0;
242     s_out_buf.u4_timestamp_low = ps_video_encode_ip->s_ive_ip.u4_timestamp_low;
243     s_out_buf.u4_timestamp_high = ps_video_encode_ip->s_ive_ip.u4_timestamp_high;
244 
245     /* api call cnt */
246     ps_codec->i4_encode_api_call_cnt += 1;
247 
248     /* codec context selector */
249     ctxt_sel = ps_codec->i4_encode_api_call_cnt % MAX_CTXT_SETS;
250 
251     /* reset status flags */
252     ps_codec->ai4_pic_cnt[ctxt_sel] = -1;
253     ps_codec->s_rate_control.post_encode_skip[ctxt_sel] = 0;
254     ps_codec->s_rate_control.pre_encode_skip[ctxt_sel] = 0;
255 
256     /* pass output buffer to codec */
257     ps_codec->as_out_buf[ctxt_sel] = s_out_buf;
258 
259     /* initialize codec ctxt with default params for the first encode api call */
260     if (ps_codec->i4_encode_api_call_cnt == 0)
261     {
262         ih264e_codec_init(ps_codec);
263     }
264 
265     /* parse configuration params */
266     for (i = 0; i < MAX_ACTIVE_CONFIG_PARAMS; i++)
267     {
268         cfg_params_t *ps_cfg = &ps_codec->as_cfg[i];
269 
270         if (1 == ps_cfg->u4_is_valid)
271         {
272             if ( ((ps_cfg->u4_timestamp_high == ps_video_encode_ip->s_ive_ip.u4_timestamp_high) &&
273                             (ps_cfg->u4_timestamp_low == ps_video_encode_ip->s_ive_ip.u4_timestamp_low)) ||
274                             ((WORD32)ps_cfg->u4_timestamp_high == -1) ||
275                             ((WORD32)ps_cfg->u4_timestamp_low == -1) )
276             {
277                 error_status |= ih264e_codec_update_config(ps_codec, ps_cfg);
278                 SET_ERROR_ON_RETURN(error_status,
279                                     IVE_UNSUPPORTEDPARAM,
280                                     ps_video_encode_op->s_ive_op.u4_error_code,
281                                     IV_FAIL);
282 
283                 ps_cfg->u4_is_valid = 0;
284             }
285         }
286     }
287 
288     /******************************************************************
289      * INSERT LOGO
290      *****************************************************************/
291 #ifdef LOGO_EN
292     if (s_inp_buf.s_raw_buf.apv_bufs[0] != NULL &&
293                     ps_codec->i4_header_mode != 1)
294     {
295         ih264e_insert_logo(s_inp_buf.s_raw_buf.apv_bufs[0],
296                            s_inp_buf.s_raw_buf.apv_bufs[1],
297                            s_inp_buf.s_raw_buf.apv_bufs[2],
298                            s_inp_buf.s_raw_buf.au4_strd[0],
299                            0,
300                            0,
301                            ps_codec->s_cfg.e_inp_color_fmt,
302                            ps_codec->s_cfg.u4_disp_wd,
303                            ps_codec->s_cfg.u4_disp_ht);
304     }
305 #endif /*LOGO_EN*/
306 
307     /* In case of alt ref and B pics we will have non reference frame in stream */
308     if (ps_codec->s_cfg.u4_enable_alt_ref || ps_codec->s_cfg.u4_num_bframes)
309     {
310         ps_codec->i4_non_ref_frames_in_stream = 1;
311     }
312 
313     if (ps_codec->i4_encode_api_call_cnt == 0)
314     {
315         /********************************************************************/
316         /*   number of mv/ref bank buffers used by the codec,               */
317         /*      1 to handle curr frame                                      */
318         /*      1 to store information of ref frame                         */
319         /*      1 more additional because of the codec employs 2 ctxt sets  */
320         /*        to assist asynchronous API                                */
321         /********************************************************************/
322 
323         /* initialize mv bank buffer manager */
324         error_status |= ih264e_mv_buf_mgr_add_bufs(ps_codec);
325         SET_ERROR_ON_RETURN(error_status,
326                             IVE_FATALERROR,
327                             ps_video_encode_op->s_ive_op.u4_error_code,
328                             IV_FAIL);
329 
330         /* initialize ref bank buffer manager */
331         error_status |= ih264e_pic_buf_mgr_add_bufs(ps_codec);
332         SET_ERROR_ON_RETURN(error_status,
333                             IVE_FATALERROR,
334                             ps_video_encode_op->s_ive_op.u4_error_code,
335                             IV_FAIL);
336 
337         /* for the first frame, generate header when not requested explicitly */
338         if (ps_codec->i4_header_mode == 0 &&
339                         ps_codec->u4_header_generated == 0)
340         {
341             ps_codec->i4_gen_header = 1;
342         }
343     }
344 
345     /* generate header and return when encoder is operated in header mode */
346     if (ps_codec->i4_header_mode == 1)
347     {
348         /* whenever the header is generated, this implies a start of sequence
349          * and a sequence needs to be started with IDR
350          */
351         ps_codec->force_curr_frame_type = IV_IDR_FRAME;
352 
353         /* generate header */
354         error_status |= ih264e_generate_sps_pps(ps_codec);
355 
356         /* api call cnt */
357         ps_codec->i4_encode_api_call_cnt --;
358 
359         /* header mode tag is not sticky */
360         ps_codec->i4_header_mode = 0;
361         ps_codec->i4_gen_header = 0;
362 
363         /* send the input to app */
364         ps_video_encode_op->s_ive_op.s_inp_buf = ps_video_encode_ip->s_ive_ip.s_inp_buf;
365         ps_video_encode_op->s_ive_op.u4_timestamp_low = ps_video_encode_ip->s_ive_ip.u4_timestamp_low;
366         ps_video_encode_op->s_ive_op.u4_timestamp_high = ps_video_encode_ip->s_ive_ip.u4_timestamp_high;
367 
368         ps_video_encode_op->s_ive_op.u4_is_last = ps_video_encode_ip->s_ive_ip.u4_is_last;
369 
370         /* send the output to app */
371         ps_video_encode_op->s_ive_op.output_present  = 1;
372         ps_video_encode_op->s_ive_op.dump_recon = 0;
373         ps_video_encode_op->s_ive_op.s_out_buf = ps_codec->as_out_buf[ctxt_sel].s_bits_buf;
374 
375         /* error status */
376         SET_ERROR_ON_RETURN(error_status,
377                             IVE_FATALERROR,
378                             ps_video_encode_op->s_ive_op.u4_error_code,
379                             IV_FAIL);
380 
381         /* indicates that header has been generated previously */
382         ps_codec->u4_header_generated = 1;
383 
384         return IV_SUCCESS;
385     }
386 
387     /* curr pic cnt */
388      ps_codec->i4_pic_cnt += 1;
389 
390     i4_rc_pre_enc_skip = 0;
391     i4_rc_pre_enc_skip = ih264e_input_queue_update(
392                     ps_codec, &ps_video_encode_ip->s_ive_ip, &s_inp_buf);
393 
394     s_out_buf.u4_is_last = s_inp_buf.u4_is_last;
395     ps_video_encode_op->s_ive_op.u4_is_last = s_inp_buf.u4_is_last;
396 
397     /* Only encode if the current frame is not pre-encode skip */
398     if (!i4_rc_pre_enc_skip && s_inp_buf.s_raw_buf.apv_bufs[0])
399     {
400         /* proc ctxt base idx */
401         WORD32 proc_ctxt_select = ctxt_sel * MAX_PROCESS_THREADS;
402 
403         /* proc ctxt */
404         process_ctxt_t *ps_proc = &ps_codec->as_process[proc_ctxt_select];
405 
406         WORD32 ret = 0;
407 
408         /* number of addl. threads to be created */
409         WORD32 num_thread_cnt = ps_codec->s_cfg.u4_num_cores - 1;
410 
411         /* array giving pic cnt that is being processed in curr context set */
412         ps_codec->ai4_pic_cnt[ctxt_sel] = ps_codec->i4_pic_cnt;
413 
414         /* initialize all relevant process ctxts */
415         error_status |= ih264e_pic_init(ps_codec, &s_inp_buf);
416         SET_ERROR_ON_RETURN(error_status,
417                             IVE_FATALERROR,
418                             ps_video_encode_op->s_ive_op.u4_error_code,
419                             IV_FAIL);
420 
421         for (i = 0; i < num_thread_cnt; i++)
422         {
423             ret = ithread_create(ps_codec->apv_proc_thread_handle[i],
424                                  NULL,
425                                  (void *)ih264e_process_thread,
426                                  &ps_codec->as_process[i + 1]);
427             if (ret != 0)
428             {
429                 printf("pthread Create Failed");
430                 assert(0);
431             }
432 
433             ps_codec->ai4_process_thread_created[i] = 1;
434 
435             ps_codec->i4_proc_thread_cnt++;
436         }
437 
438 
439         /* launch job */
440         ih264e_process_thread(ps_proc);
441 
442         /* Join threads at the end of encoding a frame */
443         ih264e_join_threads(ps_codec);
444 
445         ih264_list_reset(ps_codec->pv_proc_jobq);
446 
447         ih264_list_reset(ps_codec->pv_entropy_jobq);
448     }
449 
450 
451    /****************************************************************************
452    * RECON
453    *    Since we have forward dependent frames, we cannot return recon in encoding
454    *    order. It must be in poc order, or input pic order. To achieve this we
455    *    introduce a delay of 1 to the recon wrt encode. Now since we have that
456    *    delay, at any point minimum of pic_cnt in our ref buffer will be the
457    *    correct frame. For ex let our GOP be IBBP [1 2 3 4] . The encode order
458    *    will be [1 4 2 3] .Now since we have a delay of 1, when we are done with
459    *    encoding 4, the min in the list will be 1. After encoding 2, it will be
460    *    2, 3 after 3 and 4 after 4. Hence we can return in sequence. Note
461    *    that the 1 delay is critical. Hence if we have post enc skip, we must
462    *    skip here too. Note that since post enc skip already frees the recon
463    *    buffer we need not do any thing here
464    *
465    *    We need to return a recon when ever we consume an input buffer. This
466    *    comsumption include a pre or post enc skip. Thus dump recon is set for
467    *    all cases except when
468    *    1) We are waiting -> ps_codec->i4_frame_num > 1
469    *    2) When the input buffer is null [ ie we are not consuming any inp]
470    *        An exception need to be made for the case when we have the last buffer
471    *        since we need to flush out the on remainig recon.
472    ****************************************************************************/
473 
474     ps_video_encode_op->s_ive_op.dump_recon = 0;
475 
476     if (ps_codec->s_cfg.u4_enable_recon && (ps_codec->i4_frame_num > 1 || s_inp_buf.u4_is_last)
477                     && (s_inp_buf.s_raw_buf.apv_bufs[0] || s_inp_buf.u4_is_last))
478     {
479         /* error status */
480         IH264_ERROR_T ret = IH264_SUCCESS;
481         pic_buf_t *ps_pic_buf = NULL;
482         WORD32 i4_buf_status, i4_curr_poc = 32768;
483 
484         /* In case of skips we return recon, but indicate that buffer is zero size */
485         if (ps_codec->s_rate_control.post_encode_skip[ctxt_sel]
486                         || i4_rc_pre_enc_skip)
487         {
488 
489             ps_video_encode_op->s_ive_op.dump_recon = 1;
490             ps_video_encode_op->s_ive_op.s_recon_buf.au4_wd[0] = 0;
491             ps_video_encode_op->s_ive_op.s_recon_buf.au4_wd[1] = 0;
492 
493         }
494         else
495         {
496             for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
497             {
498                 if (ps_codec->as_ref_set[i].i4_pic_cnt == -1)
499                     continue;
500 
501                 i4_buf_status = ih264_buf_mgr_get_status(
502                                 ps_codec->pv_ref_buf_mgr,
503                                 ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id);
504 
505                 if ((i4_buf_status & BUF_MGR_IO)
506                                 && (ps_codec->as_ref_set[i].i4_poc < i4_curr_poc))
507                 {
508                     ps_pic_buf = ps_codec->as_ref_set[i].ps_pic_buf;
509                     i4_curr_poc = ps_codec->as_ref_set[i].i4_poc;
510                 }
511             }
512 
513             ps_video_encode_op->s_ive_op.s_recon_buf =
514                             ps_video_encode_ip->s_ive_ip.s_recon_buf;
515 
516             /*
517              * If we get a valid buffer. output and free recon.
518              *
519              * we may get an invalid buffer if num_b_frames is 0. This is because
520              * We assume that there will be a ref frame in ref list after encoding
521              * the last frame. With B frames this is correct since its forward ref
522              * pic will be in the ref list. But if num_b_frames is 0, we will not
523              * have a forward ref pic
524              */
525 
526             if (ps_pic_buf)
527             {
528                 /* copy/convert the recon buffer and return */
529                 ih264e_fmt_conv(ps_codec,
530                                 ps_pic_buf,
531                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.apv_bufs[0],
532                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.apv_bufs[1],
533                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.apv_bufs[2],
534                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.au4_wd[0],
535                                 ps_video_encode_ip->s_ive_ip.s_recon_buf.au4_wd[1],
536                                 0, ps_codec->s_cfg.u4_disp_ht);
537 
538                 ps_video_encode_op->s_ive_op.dump_recon = 1;
539 
540                 ret = ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr,
541                                             ps_pic_buf->i4_buf_id, BUF_MGR_IO);
542 
543                 if (IH264_SUCCESS != ret)
544                 {
545                     SET_ERROR_ON_RETURN(
546                                     (IH264E_ERROR_T)ret, IVE_FATALERROR,
547                                     ps_video_encode_op->s_ive_op.u4_error_code,
548                                     IV_FAIL);
549                 }
550             }
551         }
552     }
553 
554 
555     /***************************************************************************
556      * Free reference buffers:
557      * In case of a post enc skip, we have to ensure that those pics will not
558      * be used as reference anymore. In all other cases we will not even mark
559      * the ref buffers
560      ***************************************************************************/
561     if (ps_codec->s_rate_control.post_encode_skip[ctxt_sel])
562     {
563         /* pic info */
564         pic_buf_t *ps_cur_pic;
565 
566         /* mv info */
567         mv_buf_t *ps_cur_mv_buf;
568 
569         /* error status */
570         IH264_ERROR_T ret = IH264_SUCCESS;
571 
572         /* Decrement coded pic count */
573         ps_codec->i4_poc--;
574 
575         /* loop through to get the min pic cnt among the list of pics stored in ref list */
576         /* since the skipped frame may not be on reference list, we may not have an MV bank
577          * hence free only if we have allocated */
578         for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
579         {
580             if (ps_codec->i4_pic_cnt == ps_codec->as_ref_set[i].i4_pic_cnt)
581             {
582 
583                 ps_cur_pic = ps_codec->as_ref_set[i].ps_pic_buf;
584 
585                 ps_cur_mv_buf = ps_codec->as_ref_set[i].ps_mv_buf;
586 
587                 /* release this frame from reference list and recon list */
588                 ret = ih264_buf_mgr_release(ps_codec->pv_mv_buf_mgr, ps_cur_mv_buf->i4_buf_id , BUF_MGR_REF);
589                 ret |= ih264_buf_mgr_release(ps_codec->pv_mv_buf_mgr, ps_cur_mv_buf->i4_buf_id , BUF_MGR_IO);
590                 SET_ERROR_ON_RETURN((IH264E_ERROR_T)ret,
591                                     IVE_FATALERROR,
592                                     ps_video_encode_op->s_ive_op.u4_error_code,
593                                     IV_FAIL);
594 
595                 ret = ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr, ps_cur_pic->i4_buf_id , BUF_MGR_REF);
596                 ret |= ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr, ps_cur_pic->i4_buf_id , BUF_MGR_IO);
597                 SET_ERROR_ON_RETURN((IH264E_ERROR_T)ret,
598                                     IVE_FATALERROR,
599                                     ps_video_encode_op->s_ive_op.u4_error_code,
600                                     IV_FAIL);
601                 break;
602             }
603         }
604     }
605 
606     /*
607      * Since recon is not in sync with output, ie there can be frame to be
608      * given back as recon even after last output. Hence we need to mark that
609      * the output is not the last.
610      * Hence search through reflist and mark appropriately
611      */
612     if (ps_codec->s_cfg.u4_enable_recon)
613     {
614         WORD32 i4_buf_status = 0;
615 
616         for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
617         {
618             if (ps_codec->as_ref_set[i].i4_pic_cnt == -1)
619                 continue;
620 
621             i4_buf_status |= ih264_buf_mgr_get_status(
622                             ps_codec->pv_ref_buf_mgr,
623                             ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id);
624         }
625 
626         if (i4_buf_status & BUF_MGR_IO)
627         {
628             s_out_buf.u4_is_last = 0;
629             ps_video_encode_op->s_ive_op.u4_is_last = 0;
630         }
631     }
632 
633 
634     /**************************************************************************
635      * Signaling to APP
636      *  1) If we valid a valid output mark it so
637      *  2) Set the codec output ps_video_encode_op
638      *  3) Set the error status
639      *  4) Set the return Pic type
640      *      Note that we already has marked recon properly
641      *  5)Send the consumed input back to app so that it can free it if possible
642      *
643      *  We will have to return the output and input buffers unconditionally
644      *  so that app can release them
645      **************************************************************************/
646     if (!i4_rc_pre_enc_skip
647                     && !ps_codec->s_rate_control.post_encode_skip[ctxt_sel]
648                     && s_inp_buf.s_raw_buf.apv_bufs[0])
649     {
650 
651         /* receive output back from codec */
652         s_out_buf = ps_codec->as_out_buf[ctxt_sel];
653 
654         /* send the output to app */
655         ps_video_encode_op->s_ive_op.output_present  = 1;
656         ps_video_encode_op->s_ive_op.u4_error_code = IV_SUCCESS;
657 
658         /* Set the time stamps of the encodec input */
659         ps_video_encode_op->s_ive_op.u4_timestamp_low = s_inp_buf.u4_timestamp_low;
660         ps_video_encode_op->s_ive_op.u4_timestamp_high = s_inp_buf.u4_timestamp_high;
661 
662 
663         switch (ps_codec->pic_type)
664         {
665             case PIC_IDR:
666                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type =IV_IDR_FRAME;
667                 break;
668 
669             case PIC_I:
670                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_I_FRAME;
671                 break;
672 
673             case PIC_P:
674                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_P_FRAME;
675                 break;
676 
677             case PIC_B:
678                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_B_FRAME;
679                 break;
680 
681             default:
682                 ps_video_encode_op->s_ive_op.u4_encoded_frame_type = IV_NA_FRAME;
683                 break;
684         }
685 
686         for (i = 0; i < (WORD32)ps_codec->s_cfg.u4_num_cores; i++)
687         {
688             error_status |= ps_codec->as_process[ctxt_sel + i].i4_error_code;
689         }
690         SET_ERROR_ON_RETURN(error_status,
691                             IVE_FATALERROR,
692                             ps_video_encode_op->s_ive_op.u4_error_code,
693                             IV_FAIL);
694     }
695     else
696     {
697         /* proc ctxt base idx */
698         WORD32 proc_ctxt_select = ctxt_sel * MAX_PROCESS_THREADS;
699 
700         /* proc ctxt */
701         process_ctxt_t *ps_proc = &ps_codec->as_process[proc_ctxt_select];
702 
703         /* receive output back from codec */
704         s_out_buf = ps_codec->as_out_buf[ctxt_sel];
705 
706         ps_video_encode_op->s_ive_op.output_present = 0;
707         ps_video_encode_op->s_ive_op.u4_error_code = IV_SUCCESS;
708 
709         /* Set the time stamps of the encodec input */
710         ps_video_encode_op->s_ive_op.u4_timestamp_low = 0;
711         ps_video_encode_op->s_ive_op.u4_timestamp_high = 0;
712 
713         /* receive input back from codec and send it to app */
714         s_inp_buf = ps_proc->s_inp_buf;
715         ps_video_encode_op->s_ive_op.s_inp_buf = s_inp_buf.s_raw_buf;
716 
717         ps_video_encode_op->s_ive_op.u4_encoded_frame_type =  IV_NA_FRAME;
718 
719     }
720 
721     /* Send the input to encoder so that it can free it if possible */
722     ps_video_encode_op->s_ive_op.s_out_buf = s_out_buf.s_bits_buf;
723     ps_video_encode_op->s_ive_op.s_inp_buf = s_inp_buf.s_raw_buf;
724 
725 
726     if (1 == s_inp_buf.u4_is_last)
727     {
728         ps_video_encode_op->s_ive_op.output_present = 0;
729         ps_video_encode_op->s_ive_op.dump_recon = 0;
730     }
731 
732     return IV_SUCCESS;
733 }
734