Libmix:  Fixed surface pool allocation

BZ: 4928, 4144

Changes to frame manager and AVC object to correctly support AVC specification

Change-Id: Id80920257f08fbec7b0c8d58eed12d98af8fe51c
diff --git a/mix_video/src/mixframemanager.cpp b/mix_video/src/mixframemanager.cpp
index adfc53e..cbd2439 100644
--- a/mix_video/src/mixframemanager.cpp
+++ b/mix_video/src/mixframemanager.cpp
@@ -44,6 +44,7 @@
         ,next_frame_picnumber(0)
         ,max_enqueue_size(MIX_MAX_ENQUEUE_SIZE)
         ,max_picture_number((uint32)-1)
+        ,dpb_size((uint32)-1)
         ,ref_count(1) {
 }
 
@@ -186,6 +187,15 @@
     return MIX_RESULT_SUCCESS;
 }
 
+MIX_RESULT mix_framemanager_set_dpb_size(
+    MixFrameManager *fm, uint32 num) {
+    fm->mLock.lock();
+    fm->dpb_size = num < MIX_MAX_ENQUEUE_SIZE ? num : MIX_MAX_ENQUEUE_SIZE;
+    LOG_V("dpb is %d\n", fm->dpb_size);
+    fm->mLock.unlock();
+    return MIX_RESULT_SUCCESS;
+}
+
 
 MIX_RESULT mix_framemanager_flush(MixFrameManager *fm) {
     MixVideoFrame *frame = NULL;
@@ -466,11 +476,15 @@
 {
     int i, len;
     MixVideoFrame* p;
+    MixVideoFrame* outp;
+    int outpicnum;
+    int prevpicnum;
     uint32 picnum;
     uint32 next_picnum_pending;
 
     int least_poc_index;
     uint32 least_poc;
+    uint32 maxframeinqueue;
 
     len = j_slist_length(fm->frame_list);
 
@@ -479,61 +493,56 @@
     least_poc_index = -1;
     least_poc = (uint32)-1;
 
-    for (i = 0; i < len; )
+    if ((fm->dpb_size == -1) || (fm->dpb_size == len))
     {
-        p = (MixVideoFrame*)j_slist_nth_data(fm->frame_list, i);
-        mix_videoframe_get_displayorder(p, &picnum);
-        if (picnum == fm->next_frame_picnumber)
-        {
-            fm->frame_list = j_slist_remove(fm->frame_list, p);
-            mix_framemanager_update_timestamp(fm, p);
-            *mvf = p;
-            LOG_V("frame is dequeued, poc = %d.\n", fm->next_frame_picnumber);
-            fm->next_frame_picnumber++;
-            //if (fm->next_frame_picnumber == fm->max_picture_number)
-            //    fm->next_frame_picnumber = 0;
-            return MIX_RESULT_SUCCESS;
-        }
-
-        if(picnum == 0) {
-            if(i == 0) {
-                fm->next_frame_picnumber = 0;
-            } else {
-                fm->next_frame_picnumber = least_poc;
-                i = least_poc_index;
-            }
-            continue;
-        }
-        if(picnum < least_poc) {
-            least_poc = picnum;
-            least_poc_index = i;
-            LOG_V("least_poc_index = %d\n", least_poc_index);
-        }
-
-        ++i;
-
-        if (picnum > fm->next_frame_picnumber &&
-                picnum < next_picnum_pending)
-        {
-            next_picnum_pending = picnum;
-        }
-
-        if (picnum < fm->next_frame_picnumber &&
-                fm->next_frame_picnumber - picnum < 8)
-        {
-            // the smallest value of "max_pic_order_cnt_lsb_minus4" is 16. If the distance of "next frame pic number"
-            // to the pic number  in the list is less than half of 16, it is safe to assume that pic number
-            // is reset when a new IDR is encoded. (where pic numbfer of top or bottom field must be 0, subclause 8.2.1).
-            LOG_V("picture number is reset to %d, next pic number is %d, next pending number is %d.\n",
-                  picnum, fm->next_frame_picnumber, next_picnum_pending);
-            break;
-        }
+        maxframeinqueue = len;
+        maxframeinqueue = (maxframeinqueue < (MIX_MAX_ENQUEUE_SIZE + 1)) ? maxframeinqueue : (MIX_MAX_ENQUEUE_SIZE + 1);
+    }
+    else
+    {
+        maxframeinqueue = 0;
     }
 
+    if (maxframeinqueue)
+    {
+        p = (MixVideoFrame*)j_slist_nth_data(fm->frame_list, 0);
+        mix_videoframe_get_displayorder(p, &picnum);
+        outpicnum = picnum;
+        prevpicnum = picnum;
+        outp = p;
+
+        for (i = 1; i < maxframeinqueue;i++ )
+        {
+            p = (MixVideoFrame*)j_slist_nth_data(fm->frame_list, i);
+            mix_videoframe_get_displayorder(p, &picnum);
+
+            if (picnum ==0)
+            {
+                break;
+            }
+            else if (picnum < outpicnum)
+            {
+                outpicnum = picnum;
+                outp = p;
+                prevpicnum = picnum;
+            }
+            else //(picnum >= outpicnum)
+            {
+                prevpicnum = picnum;
+            }
+        }
+
+        fm->frame_list = j_slist_remove(fm->frame_list, (void *)outp);
+        mix_framemanager_update_timestamp(fm, outp);
+        *mvf = outp;
+
+
+        return MIX_RESULT_SUCCESS;
+    }
     if (len <= fm->max_enqueue_size && fm->eos == FALSE)
     {
         LOG_V("No frame is dequeued. Expected POC = %d, next pending POC = %d. (List size = %d)\n",
-              fm->next_frame_picnumber, next_picnum_pending, len);
+                fm->next_frame_picnumber, next_picnum_pending, len);
         return MIX_RESULT_FRAME_NOTAVAIL;
     }
 
@@ -541,7 +550,7 @@
     if (next_picnum_pending != (uint32)-1)
     {
         LOG_V("picture number has gap, jumping from %d to %d.\n",
-              fm->next_frame_picnumber, next_picnum_pending);
+                fm->next_frame_picnumber, next_picnum_pending);
 
         fm->next_frame_picnumber = next_picnum_pending;
         goto retry;
@@ -549,7 +558,7 @@
 
     // picture number roll-over
     LOG_V("picture number is rolled over, resetting next picnum from %d to 0.\n",
-          fm->next_frame_picnumber);
+        fm->next_frame_picnumber);
 
     fm->next_frame_picnumber = 0;
     goto retry;
diff --git a/mix_video/src/mixframemanager.h b/mix_video/src/mixframemanager.h
index 684857d..ca49ef0 100644
--- a/mix_video/src/mixframemanager.h
+++ b/mix_video/src/mixframemanager.h
@@ -52,6 +52,7 @@
     int    max_enqueue_size;
     uint32 max_picture_number;
     uint32 ref_count;
+    int    dpb_size;
 };
 
 
@@ -119,6 +120,8 @@
 MIX_RESULT mix_framemanager_set_max_picture_number(
     MixFrameManager *fm, uint32 num);
 
+MIX_RESULT mix_framemanager_set_dpb_size(
+    MixFrameManager *fm, uint32 num);
 
 /*
  * Get Display Order Mode
diff --git a/mix_video/src/mixvideoformat_h264.cpp b/mix_video/src/mixvideoformat_h264.cpp
index 0bbe19a..158c456 100644
--- a/mix_video/src/mixvideoformat_h264.cpp
+++ b/mix_video/src/mixvideoformat_h264.cpp
@@ -349,6 +349,7 @@
     Unlock();
     //Call Frame Manager with _eos()
     ret = mix_framemanager_eos(this->framemgr);
+    mix_framemanager_set_dpb_size(this->framemgr, -1);
     LOG_V( "End\n");
     return ret;
 }
@@ -484,10 +485,94 @@
         num_ref_pictures = data->codec_data->num_ref_frames;
     }
 
+    int pic_size;
+    int size = 3;
+    if (data)
+    {
+        pic_size = (data->pic_data[0].pic_parms->picture_width_in_mbs_minus1 + 1) * (data->pic_data[0].pic_parms->picture_height_in_mbs_minus1 + 1) * (data->codec_data->frame_mbs_only_flag?1:2) * 384;
+
+        switch (data->codec_data->level_idc)
+        {
+        case 9:
+        size = 152064;
+        break;
+        case 10:
+        size = 152064;
+        break;
+        case 11:
+            size = 345600;
+        break;
+        case 12:
+        size = 912384;
+        break;
+        case 13:
+        size = 912384;
+        break;
+        case 20:
+        size = 912384;
+        break;
+        case 21:
+        size = 1824768;
+        break;
+        case 22:
+        size = 3110400;
+        break;
+        case 30:
+        size = 3110400;
+        break;
+        case 31:
+        size = 6912000;
+        break;
+        case 32:
+        size = 7864320;
+        break;
+        case 40:
+        size = 12582912;
+        break;
+        case 41:
+        size = 12582912;
+        break;
+        case 42:
+        size = 13369344;
+        break;
+        case 50:
+        size = 42393600;
+        break;
+        case 51:
+        size = 70778880;
+        break;
+        default:
+        //error ("undefined level", 500);
+        break;
+        }
+
+        if (pic_size)
+        {
+            size /= pic_size;
+            if (size == 0)
+            {
+                size = 3;
+            }
+            else if (size > 16)
+            {
+                size = 15;
+            }
+        }
+        else
+        {
+            size = 3;
+        }
+    }
+
+    mix_framemanager_set_dpb_size(this->framemgr, size);
+
     //Adding 1 to work around VBLANK issue, and another 1 to compensate cached frame that
     // will not start decoding until a new frame is received.
-    this->va_num_surfaces = 1 + 1 + this->extra_surfaces +
-                            (((num_ref_pictures + 3) < MIX_VIDEO_H264_SURFACE_NUM) ? (num_ref_pictures + 3) : MIX_VIDEO_H264_SURFACE_NUM);
+    this->va_num_surfaces = 1 + 1 + this->extra_surfaces + (((size + 3) <
+        MIX_VIDEO_H264_SURFACE_NUM) ?
+        (size + 3)
+        : MIX_VIDEO_H264_SURFACE_NUM);
+    this->va_num_surfaces = this->va_num_surfaces > 24 ? 24 : this->va_num_surfaces; 
 
     this->va_surfaces =
         reinterpret_cast<VASurfaceID*>(malloc(sizeof(VASurfaceID)*this->va_num_surfaces));