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