1/*--------------------------------------------------------------------------
2Copyright (c) 2010-2012, Code Aurora Forum. 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 Code Aurora 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
30#define DEBUG ALOGE
31void omx_time_stamp_reorder::set_timestamp_reorder_mode(bool mode)
32{
33	reorder_ts = mode;
34}
35
36void omx_time_stamp_reorder::enable_debug_print(bool flag)
37{
38        print_debug = flag;
39}
40
41omx_time_stamp_reorder::~omx_time_stamp_reorder()
42{
43	delete_list();
44}
45
46omx_time_stamp_reorder::omx_time_stamp_reorder()
47{
48	reorder_ts = false;
49	phead = pcurrent = NULL;
50	error = false;
51        print_debug = false;
52}
53
54void omx_time_stamp_reorder::delete_list()
55{
56	time_stamp_list *ptemp;
57	if (!phead) return;
58	while(phead->next != phead) {
59		ptemp = phead;
60		phead = phead->next;
61		phead->prev = ptemp->prev;
62		ptemp->prev->next = phead;
63		delete ptemp;
64	}
65	delete phead;
66	phead = NULL;
67}
68
69bool omx_time_stamp_reorder::get_current_list()
70{
71	if (!phead) {
72		if(!add_new_list()) {
73			handle_error();
74			return false;
75		}
76	}
77	pcurrent = phead->prev;
78	return true;
79}
80
81bool omx_time_stamp_reorder::update_head()
82{
83	time_stamp_list *ptemp;
84	if(!phead) return false;
85	if (phead->next != phead) {
86		ptemp = phead;
87		phead = ptemp->next;
88		phead->prev = ptemp->prev;
89		ptemp->prev->next = phead;
90		delete ptemp;
91	}
92	return true;
93}
94
95bool omx_time_stamp_reorder::add_new_list()
96{
97	bool status = true;
98	time_stamp_list *ptemp = NULL;
99	if (!phead) {
100		ptemp = phead = new time_stamp_list;
101		if (!phead) {
102			handle_error();
103			status = false;
104			return status;
105		}
106		phead->prev = phead->next = phead;
107	} else {
108		ptemp = new time_stamp_list;
109		if (!ptemp) {
110			handle_error();
111			status = false;
112			return status;
113		}
114		ptemp->prev = phead->prev;
115		ptemp->next = phead;
116		phead->prev->next = ptemp;
117		phead->prev = ptemp;
118	}
119	ptemp->entries_filled = 0;
120	for(int i=0; i < TIME_SZ; i++) {
121		ptemp->input_timestamps[i].in_use = false;
122		ptemp->input_timestamps[i].timestamps = -1;
123	}
124	return status;
125}
126
127bool omx_time_stamp_reorder::insert_timestamp(OMX_BUFFERHEADERTYPE *header)
128{
129	OMX_TICKS *table_entry = NULL;
130	if (!reorder_ts || error || !header) {
131		if (error || !header)
132			DEBUG("\n Invalid condition in insert_timestamp %p", header);
133		return false;
134	}
135	if(!get_current_list()) {
136		handle_error();
137		return false;
138	}
139	if (pcurrent->entries_filled > (TIME_SZ - 1)) {
140		DEBUG("\n Table full return error");
141		handle_error();
142		return false;
143	}
144	if (header->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
145		return true;
146	}
147	if ((header->nFlags & OMX_BUFFERFLAG_EOS) && !header->nFilledLen)
148	{
149		DEBUG("\n EOS with zero length recieved");
150		if (!add_new_list()) {
151			handle_error();
152			return false;
153		}
154		return true;
155	}
156	for(int i = 0; i < TIME_SZ && !table_entry; i++) {
157		if (!pcurrent->input_timestamps[i].in_use) {
158			table_entry = &pcurrent->input_timestamps[i].timestamps;
159			pcurrent->input_timestamps[i].in_use = true;
160			pcurrent->entries_filled++;
161		}
162	}
163	if (!table_entry) {
164		DEBUG("\n All entries in use");
165		handle_error();
166		return false;
167	}
168	*table_entry = header->nTimeStamp;
169        if (print_debug)
170	        DEBUG("Time stamp inserted %lld", header->nTimeStamp);
171	if (header->nFlags & OMX_BUFFERFLAG_EOS) {
172		if (!add_new_list()) {
173			handle_error();
174			return false;
175		}
176	}
177	return true;
178}
179
180bool omx_time_stamp_reorder::remove_time_stamp(OMX_TICKS ts, bool is_interlaced = false)
181{
182	unsigned int num_ent_remove = (is_interlaced)?2:1;
183	if (!reorder_ts || error) {
184		DEBUG("\n not in avi mode");
185		return false;
186	}
187	if (!phead || !phead->entries_filled) return false;
188	for(int i=0; i < TIME_SZ && num_ent_remove; i++) {
189		if (phead->input_timestamps[i].in_use && phead->input_timestamps[i].timestamps == ts) {
190				phead->input_timestamps[i].in_use = false;
191				phead->entries_filled--;
192				num_ent_remove--;
193                                if (print_debug)
194		                       DEBUG("Removed TS %lld", ts);
195		}
196	}
197	if (!phead->entries_filled) {
198		if (!update_head()) {
199			handle_error();
200			return false;
201		}
202	}
203	return true;
204}
205
206void omx_time_stamp_reorder::flush_timestamp()
207{
208	delete_list();
209}
210
211bool omx_time_stamp_reorder::get_next_timestamp(OMX_BUFFERHEADERTYPE *header, bool is_interlaced)
212{
213	timestamp *element = NULL,*duplicate = NULL;
214	bool status = false;
215	if (!reorder_ts || error || !header) {
216		if (error || !header)
217			DEBUG("\n Invalid condition in insert_timestamp %p", header);
218		return false;
219	}
220	if(!phead || !phead->entries_filled) return false;
221	for(int i=0; i < TIME_SZ; i++) {
222		if (phead->input_timestamps[i].in_use) {
223			status = true;
224			if (!element)
225				element = &phead->input_timestamps[i];
226			else {
227				if (element->timestamps > phead->input_timestamps[i].timestamps){
228					element = &phead->input_timestamps[i];
229					duplicate = NULL;
230				} else if(element->timestamps == phead->input_timestamps[i].timestamps)
231					duplicate = &phead->input_timestamps[i];
232			}
233		}
234	}
235	if (element) {
236		phead->entries_filled--;
237		header->nTimeStamp = element->timestamps;
238                if (print_debug)
239		     DEBUG("Getnext Time stamp %lld", header->nTimeStamp);
240		element->in_use = false;
241	}
242	if(is_interlaced && duplicate) {
243		phead->entries_filled--;
244		duplicate->in_use = false;
245	}
246	else if(is_interlaced && status)
247	{
248		for(int i=0; i < TIME_SZ; i++) {
249			if (phead->input_timestamps[i].in_use) {
250				if (!duplicate)
251					duplicate = &phead->input_timestamps[i];
252				else {
253					if (duplicate->timestamps > phead->input_timestamps[i].timestamps)
254						duplicate = &phead->input_timestamps[i];
255				}
256			}
257		}
258		if (duplicate) {
259			phead->entries_filled--;
260			if (print_debug)
261				DEBUG("Getnext Duplicate Time stamp %lld", header->nTimeStamp);
262			duplicate->in_use = false;
263		}
264	}
265
266	if (!phead->entries_filled) {
267		if (!update_head()) {
268			handle_error();
269			return false;
270		}
271	}
272	return status;
273}
274