1/*--------------------------------------------------------------------------
2Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are met:
6    * Redistributions of source code must retain the above copyright
7      notice, this list of conditions and the following disclaimer.
8    * Redistributions in binary form must reproduce the above copyright
9      notice, this list of conditions and the following disclaimer in the
10      documentation and/or other materials provided with the distribution.
11    * Neither the name of The Linux Foundation nor
12      the names of its contributors may be used to endorse or promote
13      products derived from this software without specific prior written
14      permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27--------------------------------------------------------------------------*/
28#include "ts_parser.h"
29#include "vidc_debug.h"
30
31#define DEBUG DEBUG_PRINT_ERROR
32
33void omx_time_stamp_reorder::set_timestamp_reorder_mode(bool mode)
34{
35    reorder_ts = mode;
36}
37
38void omx_time_stamp_reorder::enable_debug_print(bool flag)
39{
40    print_debug = flag;
41}
42
43omx_time_stamp_reorder::~omx_time_stamp_reorder()
44{
45    delete_list();
46}
47
48omx_time_stamp_reorder::omx_time_stamp_reorder()
49{
50    reorder_ts = false;
51    phead = pcurrent = NULL;
52    error = false;
53    print_debug = false;
54}
55
56void omx_time_stamp_reorder::delete_list()
57{
58    time_stamp_list *ptemp;
59
60    if (!phead) return;
61
62    while (phead->next != phead) {
63        ptemp = phead;
64        phead = phead->next;
65        phead->prev = ptemp->prev;
66        ptemp->prev->next = phead;
67        delete ptemp;
68    }
69
70    delete phead;
71    phead = NULL;
72}
73
74bool omx_time_stamp_reorder::get_current_list()
75{
76    if (!phead) {
77        if (!add_new_list()) {
78            handle_error();
79            return false;
80        }
81    }
82
83    pcurrent = phead->prev;
84    return true;
85}
86
87bool omx_time_stamp_reorder::update_head()
88{
89    time_stamp_list *ptemp;
90
91    if (!phead) return false;
92
93    if (phead->next != phead) {
94        ptemp = phead;
95        phead = ptemp->next;
96        phead->prev = ptemp->prev;
97        ptemp->prev->next = phead;
98        delete ptemp;
99    }
100
101    return true;
102}
103
104bool omx_time_stamp_reorder::add_new_list()
105{
106    bool status = true;
107    time_stamp_list *ptemp = NULL;
108
109    if (!phead) {
110        ptemp = phead = new time_stamp_list;
111
112        if (!phead) {
113            handle_error();
114            status = false;
115            return status;
116        }
117
118        phead->prev = phead->next = phead;
119    } else {
120        ptemp = new time_stamp_list;
121
122        if (!ptemp) {
123            handle_error();
124            status = false;
125            return status;
126        }
127
128        ptemp->prev = phead->prev;
129        ptemp->next = phead;
130        phead->prev->next = ptemp;
131        phead->prev = ptemp;
132    }
133
134    ptemp->entries_filled = 0;
135
136    for (int i=0; i < TIME_SZ; i++) {
137        ptemp->input_timestamps[i].in_use = false;
138        ptemp->input_timestamps[i].timestamps = -1;
139    }
140
141    return status;
142}
143
144bool omx_time_stamp_reorder::insert_timestamp(OMX_BUFFERHEADERTYPE *header)
145{
146    OMX_TICKS *table_entry = NULL;
147
148    if (!reorder_ts || error || !header) {
149        if (error || !header)
150            DEBUG("Invalid condition in insert_timestamp %p", header);
151
152        return false;
153    }
154
155    if (!get_current_list()) {
156        handle_error();
157        return false;
158    }
159
160    if (pcurrent->entries_filled > (TIME_SZ - 1)) {
161        DEBUG("Table full return error");
162        handle_error();
163        return false;
164    }
165
166    if (header->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
167        return true;
168    }
169
170    if ((header->nFlags & OMX_BUFFERFLAG_EOS) && !header->nFilledLen) {
171        DEBUG("EOS with zero length recieved");
172
173        if (!add_new_list()) {
174            handle_error();
175            return false;
176        }
177
178        return true;
179    }
180
181    for (int i = 0; i < TIME_SZ && !table_entry; i++) {
182        if (!pcurrent->input_timestamps[i].in_use) {
183            table_entry = &pcurrent->input_timestamps[i].timestamps;
184            pcurrent->input_timestamps[i].in_use = true;
185            pcurrent->entries_filled++;
186        }
187    }
188
189    if (!table_entry) {
190        DEBUG("All entries in use");
191        handle_error();
192        return false;
193    }
194
195    *table_entry = header->nTimeStamp;
196
197    if (print_debug)
198        DEBUG("Time stamp inserted %lld", header->nTimeStamp);
199
200    if (header->nFlags & OMX_BUFFERFLAG_EOS) {
201        if (!add_new_list()) {
202            handle_error();
203            return false;
204        }
205    }
206
207    return true;
208}
209
210bool omx_time_stamp_reorder::remove_time_stamp(OMX_TICKS ts, bool is_interlaced = false)
211{
212    unsigned int num_ent_remove = (is_interlaced)?2:1;
213
214    if (!reorder_ts || error) {
215        DEBUG("not in avi mode");
216        return false;
217    }
218
219    if (!phead || !phead->entries_filled) return false;
220
221    for (int i=0; i < TIME_SZ && num_ent_remove; i++) {
222        if (phead->input_timestamps[i].in_use && phead->input_timestamps[i].timestamps == ts) {
223            phead->input_timestamps[i].in_use = false;
224            phead->entries_filled--;
225            num_ent_remove--;
226
227            if (print_debug)
228                DEBUG("Removed TS %lld", ts);
229        }
230    }
231
232    if (!phead->entries_filled) {
233        if (!update_head()) {
234            handle_error();
235            return false;
236        }
237    }
238
239    return true;
240}
241
242void omx_time_stamp_reorder::flush_timestamp()
243{
244    delete_list();
245}
246
247bool omx_time_stamp_reorder::get_next_timestamp(OMX_BUFFERHEADERTYPE *header, bool is_interlaced)
248{
249    timestamp *element = NULL,*duplicate = NULL;
250    bool status = false;
251
252    if (!reorder_ts || error || !header) {
253        if (error || !header)
254            DEBUG("Invalid condition in insert_timestamp %p", header);
255
256        return false;
257    }
258
259    if (!phead || !phead->entries_filled) return false;
260
261    for (int i=0; i < TIME_SZ; i++) {
262        if (phead->input_timestamps[i].in_use) {
263            status = true;
264
265            if (!element)
266                element = &phead->input_timestamps[i];
267            else {
268                if (element->timestamps > phead->input_timestamps[i].timestamps) {
269                    element = &phead->input_timestamps[i];
270                    duplicate = NULL;
271                } else if (element->timestamps == phead->input_timestamps[i].timestamps)
272                    duplicate = &phead->input_timestamps[i];
273            }
274        }
275    }
276
277    if (element) {
278        phead->entries_filled--;
279        header->nTimeStamp = element->timestamps;
280
281        if (print_debug)
282            DEBUG("Getnext Time stamp %lld", header->nTimeStamp);
283
284        element->in_use = false;
285    }
286
287    if (is_interlaced && duplicate) {
288        phead->entries_filled--;
289        duplicate->in_use = false;
290    } else if (is_interlaced && !duplicate) {
291        element = NULL;
292
293        for (int i=0; i < TIME_SZ; i++) {
294            if (phead->input_timestamps[i].in_use) {
295                if (!element)
296                    element = &phead->input_timestamps[i];
297                else if (element->timestamps > phead->input_timestamps[i].timestamps)
298                    element = &phead->input_timestamps[i];
299            }
300        }
301
302        if (element) {
303            phead->entries_filled--;
304            header->nTimeStamp = element->timestamps;
305            element->in_use = false;
306        }
307    }
308
309    if (!phead->entries_filled) {
310        if (!update_head()) {
311            handle_error();
312            return false;
313        }
314    }
315
316    return status;
317}
318