vcgencmd: Apply ASLR
[platform/adaptation/broadcom/libomxil-vc4.git] / containers / rcv / rcv_reader.c
1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in the
11       documentation and/or other materials provided with the distribution.
12     * Neither the name of the copyright holder nor the
13       names of its contributors may be used to endorse or promote products
14       derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "containers/core/containers_private.h"
31 #include "containers/core/containers_io_helpers.h"
32 #include "containers/core/containers_utils.h"
33 #include "containers/core/containers_index.h"
34 #include "containers/core/containers_logging.h"
35
36 /******************************************************************************
37 Defines.
38 ******************************************************************************/
39
40 #define LI32(b) (((b)[3]<<24)|((b)[2]<<16)|((b)[1]<<8)|((b)[0]))
41 #define LI24(b) (((b)[2]<<16)|((b)[1]<<8)|((b)[0]))
42
43 /******************************************************************************
44 Type definitions
45 ******************************************************************************/
46 typedef struct { 
47    unsigned int num_frames : 24;
48    unsigned int constant_c5 : 8;
49    int constant_4;
50    uint32_t struct_c;
51    uint32_t vert_size;
52    uint32_t horiz_size;
53    int constant_c;
54    uint32_t struct_b[2];
55    uint32_t framerate;
56 } RCV_FILE_HEADER_T;
57
58 typedef struct {
59    unsigned int framesize : 24;
60    unsigned int res : 7;
61    unsigned int keyframe : 1;
62    uint32_t timestamp;
63 } RCV_FRAME_HEADER_T;
64
65 typedef struct VC_CONTAINER_MODULE_T
66 {
67    VC_CONTAINER_TRACK_T *track;
68    uint8_t extradata[4];
69    uint8_t mid_frame;
70    uint32_t frame_read;
71    RCV_FRAME_HEADER_T frame;
72    VC_CONTAINER_INDEX_T *index; /* index of key frames */
73
74 } VC_CONTAINER_MODULE_T;
75
76 /******************************************************************************
77 Function prototypes
78 ******************************************************************************/
79 VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T * );
80
81 /******************************************************************************
82 Local Functions
83 ******************************************************************************/
84
85 static VC_CONTAINER_STATUS_T rcv_read_header(VC_CONTAINER_T *p_ctx)
86 {
87    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
88    RCV_FILE_HEADER_T header;
89    uint8_t dummy[36];
90
91    if(PEEK_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy)) return VC_CONTAINER_ERROR_EOS;
92
93    header.num_frames = LI24(dummy);
94    header.constant_c5 = dummy[3];
95    header.constant_4 = LI32(dummy+4);
96    
97    // extradata is just struct_c from the header
98    memcpy(module->extradata, dummy+8, 4);
99    module->track->format->extradata = module->extradata;
100    module->track->format->extradata_size = 4;
101
102    module->track->format->type->video.height = LI32(dummy+12);
103    module->track->format->type->video.width = LI32(dummy+16);
104    
105    header.constant_c = LI32(dummy+20);
106    memcpy(header.struct_b, dummy+24, 8);
107    header.framerate = LI32(dummy+32);
108  
109    if(header.constant_c5 != 0xc5 || header.constant_4 != 0x4 || header.constant_c != 0xc)
110       return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
111
112    if(header.framerate != 0 && header.framerate != 0xffffffffUL)
113    {
114       module->track->format->type->video.frame_rate_num = header.framerate;
115       module->track->format->type->video.frame_rate_den = 1;
116    }
117
118    // fill in general information
119    if(header.num_frames != (1<<24)-1 && header.framerate != 0 && header.framerate != 0xffffffffUL)
120       p_ctx->duration = ((int64_t) header.num_frames * 1000000LL) / (int64_t) header.framerate;
121
122    // we're happy that this is an rcv file
123    SKIP_BYTES(p_ctx, sizeof(dummy));
124
125    return STREAM_STATUS(p_ctx);
126 }
127
128 /*****************************************************************************
129  * Utility function to seek to the keyframe nearest the given timestamp.
130  *
131  * @param p_ctx     Pointer to the container context.
132  * @param timestamp The requested time.  On success, this is updated with the time of the selected keyframe.
133  * @param later     If true, the selected frame is the earliest keyframe with a time greater or equal to timestamp.
134  *                  If false, the selected frame is the latest keyframe with a time earlier or equal to timestamp.
135  * @return          Status code.
136  */
137 static VC_CONTAINER_STATUS_T rcv_seek_nearest_keyframe(VC_CONTAINER_T *p_ctx, int64_t *timestamp, int later)
138 {
139    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
140    VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
141    int64_t prev_keyframe_offset = sizeof(RCV_FILE_HEADER_T); /* set to very first frame */
142    int64_t prev_keyframe_timestamp = 0;
143    int use_prev_keyframe = !later;
144
145    if(use_prev_keyframe || (module->frame.timestamp * 1000LL > *timestamp))
146    {
147       /* A seek has been requested to an earlier keyframe, so rewind to the beginning
148        * of the stream since there's no information available on previous frames */
149       SEEK(p_ctx, sizeof(RCV_FILE_HEADER_T));
150       memset(&module->frame, 0, sizeof(RCV_FRAME_HEADER_T));
151       module->mid_frame = 0;
152       module->frame_read = 0;
153    }
154
155    if(module->mid_frame)
156    {
157       /* Seek back to the start of the current frame */
158       SEEK(p_ctx, STREAM_POSITION(p_ctx) - module->frame_read - sizeof(RCV_FILE_HEADER_T));
159       module->mid_frame = 0;
160       module->frame_read = 0;
161    }
162
163    while(1)
164    {
165       if(PEEK_BYTES(p_ctx, &module->frame, sizeof(RCV_FRAME_HEADER_T)) != sizeof(RCV_FRAME_HEADER_T))
166       {
167          status = VC_CONTAINER_ERROR_EOS;
168          break;
169       }
170
171       if(module->frame.keyframe)
172       {
173          if(module->index)
174             vc_container_index_add(module->index, module->frame.timestamp * 1000LL, STREAM_POSITION(p_ctx));
175
176          if((module->frame.timestamp * 1000LL) >= *timestamp)
177          {
178             if((module->frame.timestamp * 1000LL) == *timestamp)
179                use_prev_keyframe = 0;
180
181             *timestamp = module->frame.timestamp * 1000LL;
182
183             break;
184          }
185
186          prev_keyframe_offset = STREAM_POSITION(p_ctx);
187          prev_keyframe_timestamp = module->frame.timestamp * 1000LL;
188       }
189
190       SKIP_BYTES(p_ctx, module->frame.framesize + sizeof(RCV_FRAME_HEADER_T));
191    }
192
193    if(use_prev_keyframe)
194    {
195       *timestamp = prev_keyframe_timestamp;
196       status = SEEK(p_ctx, prev_keyframe_offset);
197    }
198
199    return status;
200 }
201
202 /*****************************************************************************
203 Functions exported as part of the Container Module API
204 *****************************************************************************/
205 static VC_CONTAINER_STATUS_T rcv_reader_read( VC_CONTAINER_T *p_ctx,
206    VC_CONTAINER_PACKET_T *packet, uint32_t flags )
207 {
208    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
209    unsigned int size;
210
211    if(!module->mid_frame)
212    {
213       /* Save the current position for updating the indexer */
214       int64_t position = STREAM_POSITION(p_ctx);
215
216       if(READ_BYTES(p_ctx, &module->frame, sizeof(RCV_FRAME_HEADER_T)) != sizeof(RCV_FRAME_HEADER_T))
217          return VC_CONTAINER_ERROR_EOS;
218       module->mid_frame = 1;
219       module->frame_read = 0;
220
221       if(module->index && module->frame.keyframe)
222          vc_container_index_add(module->index, (int64_t)module->frame.timestamp * 1000LL, position);
223    }
224
225    packet->size = module->frame.framesize;
226    packet->dts = packet->pts = module->frame.timestamp * 1000LL;
227    packet->track = 0;
228    packet->flags = 0;
229    if(module->frame_read == 0)
230       packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
231    if(module->frame.keyframe)
232       packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
233
234    if(flags & VC_CONTAINER_READ_FLAG_SKIP)
235    {
236       size = SKIP_BYTES(p_ctx, module->frame.framesize - module->frame_read);
237       if((module->frame_read += size) == module->frame.framesize)
238       {
239          module->frame_read = 0;
240          module->mid_frame = 0;
241       }      
242       return STREAM_STATUS(p_ctx);
243    }
244
245    if(flags & VC_CONTAINER_READ_FLAG_INFO)
246       return VC_CONTAINER_SUCCESS;
247
248    size = MIN(module->frame.framesize - module->frame_read, packet->buffer_size);
249    size = READ_BYTES(p_ctx, packet->data, size);
250    if((module->frame_read += size) == module->frame.framesize)
251    {
252       module->frame_read = 0;
253       module->mid_frame = 0;
254       packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
255    }      
256    packet->size = size;
257
258    return size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(p_ctx);
259 }
260
261 /*****************************************************************************/
262 static VC_CONTAINER_STATUS_T rcv_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *offset,
263    VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
264 {
265    int past = 1;
266    int64_t position;
267    int64_t timestamp = *offset;
268    VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FAILED;
269    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
270    VC_CONTAINER_PARAM_UNUSED(mode);
271
272    if(module->index)
273       status = vc_container_index_get(module->index, flags & VC_CONTAINER_SEEK_FLAG_FORWARD, &timestamp, &position, &past);
274
275    if(status == VC_CONTAINER_SUCCESS && !past)
276    {
277       /* Indexed keyframe found */
278       module->frame_read = 0;
279       module->mid_frame = 0;
280       *offset = timestamp;
281       status = SEEK(p_ctx, position);
282    }
283    else
284    {
285       /* No indexed keyframe found, so seek through all frames */
286       status = rcv_seek_nearest_keyframe(p_ctx, offset, flags & VC_CONTAINER_SEEK_FLAG_FORWARD);
287    }
288
289    return status;
290 }
291
292 /*****************************************************************************/
293 static VC_CONTAINER_STATUS_T rcv_reader_close( VC_CONTAINER_T *p_ctx )
294 {
295    VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
296    for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
297       vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
298
299    if(module->index)
300       vc_container_index_free(module->index);
301
302    free(module);
303
304    return VC_CONTAINER_SUCCESS;
305 }
306
307 /*****************************************************************************/
308 VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T *p_ctx )
309 {
310    VC_CONTAINER_MODULE_T *module = 0;
311    VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
312    uint8_t dummy[8];
313
314    /* Quick check for a valid file header */
315    if((PEEK_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy)) ||
316       dummy[3] != 0xc5 || LI32(dummy+4) != 0x4)
317       return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
318
319    /* Allocate our context */
320    module = malloc(sizeof(*module));
321    if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
322    memset(module, 0, sizeof(*module));
323    p_ctx->priv->module = module;
324    p_ctx->tracks_num = 1;
325    p_ctx->tracks = &module->track;
326    p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
327    if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
328    p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
329    p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_WMV3;
330    p_ctx->tracks[0]->is_enabled = true;
331
332    if((status = rcv_read_header(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
333
334    LOG_DEBUG(p_ctx, "using rcv reader");
335
336    if(vc_container_index_create(&module->index, 512) == VC_CONTAINER_SUCCESS)
337       vc_container_index_add(module->index, 0LL, STREAM_POSITION(p_ctx));
338
339    if(STREAM_SEEKABLE(p_ctx))
340       p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
341
342    p_ctx->priv->pf_close = rcv_reader_close;
343    p_ctx->priv->pf_read = rcv_reader_read;
344    p_ctx->priv->pf_seek = rcv_reader_seek;
345    return VC_CONTAINER_SUCCESS;
346
347  error:
348    if(module) rcv_reader_close(p_ctx);
349    return status;
350 }
351
352 /********************************************************************************
353  Entrypoint function
354 ********************************************************************************/
355
356 #if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
357 # pragma weak reader_open rcv_reader_open
358 #endif