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