1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include <stdlib.h>
29#include <string.h>
30
31#include "containers/packetizers.h"
32#include "containers/core/packetizers_private.h"
33#include "containers/core/containers_common.h"
34#include "containers/core/containers_logging.h"
35#include "containers/core/containers_utils.h"
36
37/** List of registered packetizers. */
38static VC_PACKETIZER_REGISTRY_ENTRY_T *registry;
39
40/*****************************************************************************/
41void vc_packetizer_register(VC_PACKETIZER_REGISTRY_ENTRY_T *entry)
42{
43 LOG_DEBUG(0, "registering packetizer %s", entry->name);
44 entry->next = registry;
45 registry = entry;
46}
47
48/*****************************************************************************/
49static VC_CONTAINER_STATUS_T vc_packetizer_load(VC_PACKETIZER_T *p_ctx)
50{
51 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
52 VC_PACKETIZER_REGISTRY_ENTRY_T *entry;
53
54 /* Try all the packetizers until we find the right one */
55 for (entry = registry; entry; entry = entry->next)
56 {
57 status = entry->open(p_ctx);
58 if(status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED)
59 break;
60 }
61
62 return status;
63}
64
65/*****************************************************************************/
66static void vc_packetizer_unload(VC_PACKETIZER_T *p_ctx)
67{
68 VC_CONTAINER_PARAM_UNUSED(p_ctx);
69}
70
71/*****************************************************************************/
72VC_PACKETIZER_T *vc_packetizer_open( VC_CONTAINER_ES_FORMAT_T *in,
73 VC_CONTAINER_FOURCC_T out_variant, VC_CONTAINER_STATUS_T *p_status )
74{
75 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
76 VC_PACKETIZER_T *p_ctx = 0;
77
78 /* Allocate our context before trying out the different packetizers */
79 p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv));
80 if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
81 memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv));
82 p_ctx->priv = (VC_PACKETIZER_PRIVATE_T *)(p_ctx + 1);
83 bytestream_init( &p_ctx->priv->stream );
84
85 p_ctx->in = vc_container_format_create(in->extradata_size);
86 if(!p_ctx->in) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
87 p_ctx->out = vc_container_format_create(in->extradata_size);
88 if(!p_ctx->out) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
89
90 vc_container_format_copy( p_ctx->in, in, in->extradata_size );
91 p_ctx->in->extradata_size = 0;
92 vc_container_format_copy( p_ctx->out, p_ctx->in, in->extradata_size );
93 p_ctx->in->extradata_size = in->extradata_size;
94 p_ctx->out->extradata = p_ctx->in->extradata;
95 p_ctx->out->extradata_size = p_ctx->in->extradata_size;
96 p_ctx->out->codec_variant = out_variant;
97
98 vc_container_time_init(&p_ctx->priv->time, 1000000);
99
100 status = vc_packetizer_load(p_ctx);
101 if(status != VC_CONTAINER_SUCCESS)
102 goto error;
103
104 end:
105 if(p_status) *p_status = status;
106 return p_ctx;
107
108 error:
109 if(p_ctx) vc_packetizer_close(p_ctx);
110 p_ctx = NULL;
111 goto end;
112}
113
114/*****************************************************************************/
115VC_CONTAINER_STATUS_T vc_packetizer_close( VC_PACKETIZER_T *p_ctx )
116{
117 VC_CONTAINER_BYTESTREAM_T *stream;
118 VC_CONTAINER_PACKET_T *packet, *next;
119
120 if(!p_ctx) return VC_CONTAINER_SUCCESS;
121
122 stream = &p_ctx->priv->stream;
123
124 if(p_ctx->in) vc_container_format_delete(p_ctx->in);
125 if(p_ctx->out) vc_container_format_delete(p_ctx->out);
126 if(p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
127 if(p_ctx->priv->module_handle) vc_packetizer_unload(p_ctx);
128
129 /* Free the bytestream */
130 for(packet = stream->first; packet; packet = next)
131 {
132 next = packet->next;
133 if(packet->framework_data) free(packet);
134 }
135
136 free(p_ctx);
137 return VC_CONTAINER_SUCCESS;
138}
139
140/*****************************************************************************/
141VC_CONTAINER_STATUS_T vc_packetizer_push( VC_PACKETIZER_T *p_ctx,
142 VC_CONTAINER_PACKET_T *in)
143{
144 /* Do some sanity checking on packet ? */
145
146 in->framework_data = 0;
147 bytestream_push(&p_ctx->priv->stream, in);
148 return VC_CONTAINER_SUCCESS;
149}
150
151/*****************************************************************************/
152VC_CONTAINER_STATUS_T vc_packetizer_pop( VC_PACKETIZER_T *p_ctx,
153 VC_CONTAINER_PACKET_T **in, VC_PACKETIZER_FLAGS_T flags)
154{
155 VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
156 VC_CONTAINER_PACKET_T *packet, *new, **prev;
157
158 /* Release the packets which have been read */
159 while((*in = bytestream_pop(stream)) != NULL)
160 {
161 if(*in && (*in)->framework_data)
162 {
163 free(*in);
164 continue;
165 }
166
167 if(*in)
168 return VC_CONTAINER_SUCCESS;
169 }
170
171 if(!(flags & VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT))
172 return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
173
174 /* Look for the 1st non-framework packet */
175 for (packet = stream->first, prev = &stream->first;
176 packet && packet->framework_data; prev = &packet->next, packet = packet->next);
177
178 if (!packet || (packet && packet->framework_data))
179 return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
180
181 /* We'll currently alloc an internal packet for each packet the client forcefully releases.
182 * We could probably do something a bit more clever than that though. */
183 /* Replace the packet with a newly allocated one */
184 new = malloc(sizeof(*packet) + packet->size);
185 if(!new)
186 return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
187
188 *new = *packet;
189 new->framework_data = new;
190 if(!new->next)
191 stream->last = &new->next;
192 if(stream->current == packet)
193 stream->current = new;
194 *prev = new;
195 new->data = (uint8_t *)&new[1];
196 memcpy(new->data, packet->data, packet->size);
197 *in = packet;
198
199 return VC_CONTAINER_SUCCESS;
200}
201
202/*****************************************************************************/
203VC_CONTAINER_STATUS_T vc_packetizer_read( VC_PACKETIZER_T *p_ctx,
204 VC_CONTAINER_PACKET_T *packet, VC_PACKETIZER_FLAGS_T flags)
205{
206 if(!packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
207 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
208 if(!packet && (flags & VC_CONTAINER_READ_FLAG_INFO))
209 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
210 if(packet && !packet->data &&
211 (!(flags & VC_CONTAINER_READ_FLAG_INFO) &&
212 !(flags & VC_CONTAINER_READ_FLAG_SKIP)))
213 return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
214
215 /* Always having a packet structure to work with simplifies things */
216 if(!packet)
217 packet = &p_ctx->priv->packet;
218
219 return p_ctx->priv->pf_packetize(p_ctx, packet, flags);
220}
221
222/*****************************************************************************/
223VC_CONTAINER_STATUS_T vc_packetizer_reset( VC_PACKETIZER_T *p_ctx )
224{
225 VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
226
227 bytestream_skip( stream, stream->bytes - stream->current_offset - stream->offset );
228
229 if (p_ctx->priv->pf_reset)
230 return p_ctx->priv->pf_reset(p_ctx);
231 else
232 return VC_CONTAINER_SUCCESS;
233}
234