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#include <stdlib.h>
28#include <string.h>
29
30//#define ENABLE_CONTAINERS_LOG_FORMAT
31#include "containers/core/containers_private.h"
32#include "containers/core/containers_io_helpers.h"
33#include "containers/core/containers_utils.h"
34#include "containers/core/containers_writer_utils.h"
35#include "containers/core/containers_logging.h"
36#undef CONTAINER_HELPER_LOG_INDENT
37#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->object_level
38
39VC_CONTAINER_STATUS_T asf_writer_open( VC_CONTAINER_T *p_ctx );
40
41/******************************************************************************
42Defines.
43******************************************************************************/
44#define ASF_TRACKS_MAX 16
45#define ASF_OBJECT_HEADER_SIZE (16+8)
46
47/******************************************************************************
48Type definitions.
49******************************************************************************/
50typedef enum {
51 ASF_OBJECT_TYPE_UNKNOWN = 0,
52 ASF_OBJECT_TYPE_HEADER,
53 ASF_OBJECT_TYPE_FILE_PROPS,
54 ASF_OBJECT_TYPE_STREAM_PROPS,
55 ASF_OBJECT_TYPE_EXT_STREAM_PROPS,
56 ASF_OBJECT_TYPE_DATA,
57 ASF_OBJECT_TYPE_SIMPLE_INDEX,
58 ASF_OBJECT_TYPE_INDEX,
59 ASF_OBJECT_TYPE_HEADER_EXT,
60 ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL,
61 ASF_OBJECT_TYPE_CODEC_LIST,
62 ASF_OBJECT_TYPE_CONTENT_DESCRIPTION,
63 ASF_OBJECT_TYPE_EXT_CONTENT_DESCRIPTION,
64 ASF_OBJECT_TYPE_STREAM_BITRATE_PROPS,
65 ASF_OBJECT_TYPE_LANGUAGE_LIST,
66 ASF_OBJECT_TYPE_METADATA,
67 ASF_OBJECT_TYPE_PADDING,
68} ASF_OBJECT_TYPE_T;
69
70typedef struct VC_CONTAINER_TRACK_MODULE_T
71{
72 unsigned int stream_id;
73 uint64_t time_offset;
74 bool b_valid;
75
76 uint64_t index_offset;
77 uint32_t num_index_entries;
78 int64_t index_time_interval;
79} VC_CONTAINER_TRACK_MODULE_T;
80
81typedef struct VC_CONTAINER_MODULE_T
82{
83 int object_level;
84 uint32_t packet_size;
85
86 VC_CONTAINER_TRACK_T *tracks[ASF_TRACKS_MAX];
87
88 VC_CONTAINER_WRITER_EXTRAIO_T null;
89 bool b_header_done;
90
91 unsigned int current_track;
92
93} VC_CONTAINER_MODULE_T;
94
95/******************************************************************************
96Static functions within this file.
97******************************************************************************/
98static VC_CONTAINER_STATUS_T asf_write_object( VC_CONTAINER_T *p_ctx, ASF_OBJECT_TYPE_T object_type );
99static VC_CONTAINER_STATUS_T asf_write_object_header( VC_CONTAINER_T *p_ctx );
100static VC_CONTAINER_STATUS_T asf_write_object_header_ext( VC_CONTAINER_T *p_ctx );
101static VC_CONTAINER_STATUS_T asf_write_object_header_ext_internal( VC_CONTAINER_T *p_ctx );
102static VC_CONTAINER_STATUS_T asf_write_object_file_properties( VC_CONTAINER_T *p_ctx );
103static VC_CONTAINER_STATUS_T asf_write_object_stream_properties( VC_CONTAINER_T *p_ctx );
104static VC_CONTAINER_STATUS_T asf_write_object_ext_stream_properties( VC_CONTAINER_T *p_ctx );
105static VC_CONTAINER_STATUS_T asf_write_object_simple_index( VC_CONTAINER_T *p_ctx );
106static VC_CONTAINER_STATUS_T asf_write_object_index( VC_CONTAINER_T *p_ctx );
107static VC_CONTAINER_STATUS_T asf_write_object_data( VC_CONTAINER_T *p_ctx );
108#if 0
109static VC_CONTAINER_STATUS_T asf_write_object_codec_list( VC_CONTAINER_T *p_ctx );
110static VC_CONTAINER_STATUS_T asf_write_object_content_description( VC_CONTAINER_T *p_ctx );
111static VC_CONTAINER_STATUS_T asf_write_object_stream_bitrate_props( VC_CONTAINER_T *p_ctx );
112#endif
113
114static const GUID_T asf_guid_header = {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
115static const GUID_T asf_guid_file_props = {0x8CABDCA1, 0xA947, 0x11CF, {0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
116static const GUID_T asf_guid_stream_props = {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
117static const GUID_T asf_guid_ext_stream_props = {0x14E6A5CB, 0xC672, 0x4332, {0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}};
118static const GUID_T asf_guid_data = {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
119static const GUID_T asf_guid_simple_index = {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
120static const GUID_T asf_guid_index = {0xD6E229D3, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
121static const GUID_T asf_guid_header_ext = {0x5FBF03B5, 0xA92E, 0x11CF, {0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
122static const GUID_T asf_guid_codec_list = {0x86D15240, 0x311D, 0x11D0, {0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
123static const GUID_T asf_guid_content_description = {0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
124static const GUID_T asf_guid_ext_content_description = {0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
125static const GUID_T asf_guid_stream_bitrate_props = {0x7BF875CE, 0x468D, 0x11D1, {0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2}};
126static const GUID_T asf_guid_language_list = {0x7C4346A9, 0xEFE0, 0x4BFC, {0xB2, 0x29, 0x39, 0x3E, 0xDE, 0x41, 0x5C, 0x85}};
127static const GUID_T asf_guid_metadata = {0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}};
128static const GUID_T asf_guid_padding = {0x1806D474, 0xCADF, 0x4509, {0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8}};
129
130static const GUID_T asf_guid_stream_type_video = {0xBC19EFC0, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
131static const GUID_T asf_guid_stream_type_audio = {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
132static const GUID_T asf_guid_error_correction = {0x20FB5700, 0x5B55, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
133
134static struct {
135 const ASF_OBJECT_TYPE_T type;
136 const GUID_T *guid;
137 const char *psz_name;
138 VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T * );
139
140} asf_object_list[] =
141{
142 {ASF_OBJECT_TYPE_HEADER, &asf_guid_header, "header", asf_write_object_header},
143 {ASF_OBJECT_TYPE_FILE_PROPS, &asf_guid_file_props, "file properties", asf_write_object_file_properties},
144 {ASF_OBJECT_TYPE_STREAM_PROPS, &asf_guid_stream_props, "stream properties", asf_write_object_stream_properties},
145 {ASF_OBJECT_TYPE_EXT_STREAM_PROPS, &asf_guid_ext_stream_props, "extended stream properties", asf_write_object_ext_stream_properties},
146 {ASF_OBJECT_TYPE_DATA, &asf_guid_data, "data", asf_write_object_data},
147 {ASF_OBJECT_TYPE_SIMPLE_INDEX, &asf_guid_simple_index, "simple index", asf_write_object_simple_index},
148 {ASF_OBJECT_TYPE_INDEX, &asf_guid_index, "index", asf_write_object_index},
149 {ASF_OBJECT_TYPE_HEADER_EXT, &asf_guid_header_ext, "header extension", asf_write_object_header_ext},
150 {ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL, &asf_guid_header_ext, "header extension", asf_write_object_header_ext_internal},
151#if 0
152 {ASF_OBJECT_TYPE_CODEC_LIST, &asf_guid_codec_list, "codec list", asf_write_object_codec_list},
153 {ASF_OBJECT_TYPE_CONTENT_DESCRIPTION, &asf_guid_content_description, "content description", asf_write_object_content_description},
154 {ASF_OBJECT_TYPE_EXT_CONTENT_DESCRIPTION, &asf_guid_ext_content_description, "extended content description", 0},
155 {ASF_OBJECT_TYPE_STREAM_BITRATE_PROPS, &asf_guid_stream_bitrate_props, "stream bitrate properties", asf_write_object_stream_bitrate_props},
156#endif
157 {ASF_OBJECT_TYPE_UNKNOWN, 0, "unknown", 0}
158};
159
160static GUID_T guid_null;
161
162/*****************************************************************************/
163static VC_CONTAINER_STATUS_T asf_write_object( VC_CONTAINER_T *p_ctx, ASF_OBJECT_TYPE_T type )
164{
165 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
166 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
167 int64_t object_size = 0;
168 unsigned int i;
169
170 /* Find out which object we want to write */
171 for( i = 0; asf_object_list[i].type && asf_object_list[i].type != type; i++ );
172
173 /* Check we found the requested type */
174 if(!asf_object_list[i].type)
175 {
176 vc_container_assert(0);
177 return VC_CONTAINER_ERROR_CORRUPTED;
178 }
179
180 /* We need to find out the size of the object we're going to write.
181 * Because we want to be streamable, we can't just come back later to update the size field.
182 * The easiest way to find out the size of the data we're going to write is to write a dummy
183 * version of it and get the size from that. It is a bit wasteful but is so much easier and
184 * shouldn't really impact performance as there's no actual i/o involved. */
185 if(!vc_container_writer_extraio_enable(p_ctx, &module->null))
186 {
187 asf_object_list[i].pf_func(p_ctx);
188 object_size = STREAM_POSITION(p_ctx);
189 }
190 vc_container_writer_extraio_disable(p_ctx, &module->null);
191
192 /* Special case for header extension internal function */
193 if(type == ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL)
194 {
195 WRITE_U32(p_ctx, object_size, "Header Extension Data Size");
196 /* Call the object specific writing function */
197 status = asf_object_list[i].pf_func(p_ctx);
198 return status;
199 }
200
201 /* Write the object header */
202
203 if(WRITE_GUID(p_ctx, asf_object_list[i].guid, "Object ID") != sizeof(GUID_T))
204 return VC_CONTAINER_ERROR_EOS;
205
206 LOG_FORMAT(p_ctx, "Object Name: %s", asf_object_list[i].psz_name);
207
208 WRITE_U64(p_ctx, object_size + ASF_OBJECT_HEADER_SIZE, "Object Size");
209
210 module->object_level++;
211
212 /* Call the object specific writing function */
213 status = asf_object_list[i].pf_func(p_ctx);
214
215 module->object_level--;
216
217 if(status != VC_CONTAINER_SUCCESS)
218 LOG_DEBUG(p_ctx, "object %s appears to be corrupted", asf_object_list[i].psz_name);
219
220 return status;
221}
222
223static VC_CONTAINER_STATUS_T asf_write_object_header( VC_CONTAINER_T *p_ctx )
224{
225 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
226 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
227
228 WRITE_U32(p_ctx, 0, "Number of Header Objects"); /* FIXME: could use that */
229 WRITE_U8(p_ctx, 0, "Reserved1");
230 WRITE_U8(p_ctx, 0, "Reserved2");
231
232 status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_FILE_PROPS);
233 status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER_EXT);
234
235 for(module->current_track = 0; module->current_track < p_ctx->tracks_num;
236 module->current_track++)
237 {
238 status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_STREAM_PROPS);
239 }
240
241 /* Codec List */
242 /* Content Description */
243 /* Stream Bitrate Properties */
244
245 return status;
246}
247
248static VC_CONTAINER_STATUS_T asf_write_object_header_ext( VC_CONTAINER_T *p_ctx )
249{
250 WRITE_GUID(p_ctx, &guid_null, "Reserved Field 1");
251 WRITE_U16(p_ctx, 0, "Reserved Field 2");
252
253 return asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL);
254}
255
256static VC_CONTAINER_STATUS_T asf_write_object_header_ext_internal( VC_CONTAINER_T *p_ctx )
257{
258 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
259 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
260
261 for(module->current_track = 0; module->current_track < p_ctx->tracks_num;
262 module->current_track++)
263 {
264 status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_EXT_STREAM_PROPS);
265 }
266
267 return status;
268}
269
270static VC_CONTAINER_STATUS_T asf_write_object_file_properties( VC_CONTAINER_T *p_ctx )
271{
272 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
273
274 WRITE_GUID(p_ctx, &guid_null, "File ID");
275 WRITE_U64(p_ctx, 0, "File Size");
276 WRITE_U64(p_ctx, 0, "Creation Date");
277 WRITE_U64(p_ctx, 0, "Data Packets Count");
278 WRITE_U64(p_ctx, 0, "Play Duration");
279 WRITE_U64(p_ctx, 0, "Send Duration");
280 WRITE_U64(p_ctx, 0, "Preroll");
281 WRITE_U32(p_ctx, 0, "Flags");
282 WRITE_U32(p_ctx, module->packet_size, "Minimum Data Packet Size");
283 WRITE_U32(p_ctx, module->packet_size, "Maximum Data Packet Size");
284 WRITE_U32(p_ctx, 0, "Maximum Bitrate");
285
286 return VC_CONTAINER_SUCCESS;
287}
288
289static VC_CONTAINER_STATUS_T asf_write_bitmapinfoheader( VC_CONTAINER_T *p_ctx,
290 VC_CONTAINER_TRACK_T *p_track )
291{
292 uint32_t fourcc;
293
294 /* Write the preamble to the BITMAPINFOHEADER */
295 WRITE_U32(p_ctx, p_track->format->type->video.width, "Encoded Image Width");
296 WRITE_U32(p_ctx, p_track->format->type->video.height, "Encoded Image Height");
297 WRITE_U8(p_ctx, 0, "Reserved Flags");
298 WRITE_U16(p_ctx, 40 + p_track->format->extradata_size, "Format Data Size");
299
300 /* Write BITMAPINFOHEADER structure */
301 WRITE_U32(p_ctx, 40 + p_track->format->extradata_size, "Format Data Size");
302 WRITE_U32(p_ctx, p_track->format->type->video.width, "Image Width");
303 WRITE_U32(p_ctx, p_track->format->type->video.height, "Image Height");
304 WRITE_U16(p_ctx, 0, "Reserved");
305 WRITE_U16(p_ctx, 0, "Bits Per Pixel Count");
306 fourcc = codec_to_fourcc(p_track->format->codec);
307 WRITE_BYTES(p_ctx, (char *)&fourcc, 4); /* Compression ID */
308 LOG_FORMAT(p_ctx, "Compression ID: %4.4s", (char *)&fourcc);
309 WRITE_U32(p_ctx, 0, "Image Size");
310 WRITE_U32(p_ctx, 0, "Horizontal Pixels Per Meter");
311 WRITE_U32(p_ctx, 0, "Vertical Pixels Per Meter");
312 WRITE_U32(p_ctx, 0, "Colors Used Count");
313 WRITE_U32(p_ctx, 0, "Important Colors Count");
314
315 WRITE_BYTES(p_ctx, p_track->format->extradata, p_track->format->extradata_size);
316
317 return VC_CONTAINER_SUCCESS;
318}
319
320static VC_CONTAINER_STATUS_T asf_write_waveformatex( VC_CONTAINER_T *p_ctx,
321 VC_CONTAINER_TRACK_T *p_track)
322{
323 /* Write WAVEFORMATEX structure */
324 WRITE_U16(p_ctx, codec_to_waveformat(p_track->format->codec), "Codec ID");
325 WRITE_U16(p_ctx, p_track->format->type->audio.channels, "Number of Channels");
326 WRITE_U32(p_ctx, p_track->format->type->audio.sample_rate, "Samples per Second");
327 WRITE_U32(p_ctx, p_track->format->bitrate, "Average Number of Bytes Per Second");
328 WRITE_U16(p_ctx, p_track->format->type->audio.block_align, "Block Alignment");
329 WRITE_U16(p_ctx, p_track->format->type->audio.bits_per_sample, "Bits Per Sample");
330 WRITE_U16(p_ctx, p_track->format->extradata_size, "Codec Specific Data Size");
331 WRITE_BYTES(p_ctx, p_track->format->extradata, p_track->format->extradata_size);
332
333 return VC_CONTAINER_SUCCESS;
334}
335
336static VC_CONTAINER_STATUS_T asf_write_object_stream_properties( VC_CONTAINER_T *p_ctx )
337{
338 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
339 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
340 unsigned int track = module->current_track, ts_size = 0;
341 const GUID_T *p_guid = &guid_null;
342
343 if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
344 {
345 p_guid = &asf_guid_stream_type_video;
346 ts_size = 11 + 40 + p_ctx->tracks[track]->format->extradata_size;
347 }
348 else if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
349 {
350 p_guid = &asf_guid_stream_type_audio;
351 ts_size = 18 + p_ctx->tracks[track]->format->extradata_size;
352 }
353
354 WRITE_GUID(p_ctx, p_guid, "Stream Type");
355 WRITE_GUID(p_ctx, &asf_guid_error_correction, "Error Correction Type");
356 WRITE_U64(p_ctx, 0, "Time Offset");
357 WRITE_U32(p_ctx, ts_size, "Type-Specific Data Length");
358 WRITE_U32(p_ctx, 0, "Error Correction Data Length");
359 WRITE_U16(p_ctx, track + 1, "Flags");
360 WRITE_U32(p_ctx, 0, "Reserved");
361
362 /* Type-Specific Data */
363 if(ts_size)
364 {
365 if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
366 status = asf_write_bitmapinfoheader( p_ctx, p_ctx->tracks[track]);
367 else if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
368 status = asf_write_waveformatex( p_ctx, p_ctx->tracks[track]);
369 }
370
371 /* Error Correction Data */
372
373 return status;
374}
375
376static VC_CONTAINER_STATUS_T asf_write_object_ext_stream_properties( VC_CONTAINER_T *p_ctx )
377{
378 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
379
380 WRITE_U64(p_ctx, 0, "Start Time");
381 WRITE_U64(p_ctx, 0, "End Time");
382 WRITE_U32(p_ctx, 0, "Data Bitrate");
383 WRITE_U32(p_ctx, 0, "Buffer Size");
384 WRITE_U32(p_ctx, 0, "Initial Buffer Fullness");
385 WRITE_U32(p_ctx, 0, "Alternate Data Bitrate");
386 WRITE_U32(p_ctx, 0, "Alternate Buffer Size");
387 WRITE_U32(p_ctx, 0, "Alternate Initial Buffer Fullness");
388 WRITE_U32(p_ctx, 0, "Maximum Object Size");
389 WRITE_U32(p_ctx, 0, "Flags");
390 WRITE_U16(p_ctx, module->current_track + 1, "Stream Number");
391 WRITE_U16(p_ctx, 0, "Stream Language ID Index");
392 WRITE_U64(p_ctx, 0, "Average Time Per Frame");
393 WRITE_U16(p_ctx, 0, "Stream Name Count");
394 WRITE_U16(p_ctx, 0, "Payload Extension System Count");
395 /* Stream Names */
396 /* Payload Extension Systems */
397 /* Stream Properties Object */
398
399 return VC_CONTAINER_SUCCESS;
400}
401
402static VC_CONTAINER_STATUS_T asf_write_object_index( VC_CONTAINER_T *p_ctx )
403{
404 VC_CONTAINER_PARAM_UNUSED(p_ctx);
405 return VC_CONTAINER_SUCCESS;
406}
407
408static VC_CONTAINER_STATUS_T asf_write_object_simple_index( VC_CONTAINER_T *p_ctx )
409{
410 VC_CONTAINER_PARAM_UNUSED(p_ctx);
411 return VC_CONTAINER_SUCCESS;
412}
413
414static VC_CONTAINER_STATUS_T asf_write_object_data( VC_CONTAINER_T *p_ctx )
415{
416 VC_CONTAINER_PARAM_UNUSED(p_ctx);
417 return VC_CONTAINER_SUCCESS;
418}
419
420/*****************************************************************************/
421static VC_CONTAINER_STATUS_T asf_write_header( VC_CONTAINER_T *p_ctx )
422{
423 VC_CONTAINER_STATUS_T status;
424
425 /* TODO Sanity check the tracks */
426
427 status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER);
428 status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_DATA);
429
430 return status;
431}
432
433/*****************************************************************************/
434static VC_CONTAINER_STATUS_T asf_writer_write( VC_CONTAINER_T *p_ctx,
435 VC_CONTAINER_PACKET_T *p_packet )
436{
437 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
438 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
439 VC_CONTAINER_PARAM_UNUSED(p_packet);
440
441 if(!module->b_header_done)
442 {
443 module->b_header_done = true;
444 status = asf_write_header(p_ctx);
445 }
446
447 return status;
448}
449
450/*****************************************************************************/
451static VC_CONTAINER_STATUS_T asf_writer_close( VC_CONTAINER_T *p_ctx )
452{
453 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
454
455 for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
456 vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
457
458 vc_container_writer_extraio_delete(p_ctx, &module->null);
459 free(module);
460
461 return VC_CONTAINER_SUCCESS;
462}
463
464/*****************************************************************************/
465static VC_CONTAINER_STATUS_T asf_writer_add_track( VC_CONTAINER_T *p_ctx, VC_CONTAINER_ES_FORMAT_T *format )
466{
467 VC_CONTAINER_STATUS_T status;
468 VC_CONTAINER_TRACK_T *track;
469
470 /* TODO check we support this format */
471
472 if(!(format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
473 return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
474
475 /* Allocate and initialise track data */
476 if(p_ctx->tracks_num >= ASF_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
477 p_ctx->tracks[p_ctx->tracks_num] = track =
478 vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
479 if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
480
481 if(format->extradata_size)
482 {
483 status = vc_container_track_allocate_extradata( p_ctx, track, format->extradata_size );
484 if(status) goto error;
485 }
486
487 vc_container_format_copy(track->format, format, format->extradata_size);
488 p_ctx->tracks_num++;
489 return VC_CONTAINER_SUCCESS;
490
491 error:
492 vc_container_free_track(p_ctx, track);
493 return status;
494}
495
496/*****************************************************************************/
497static VC_CONTAINER_STATUS_T asf_writer_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, va_list args )
498{
499 VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
500 VC_CONTAINER_STATUS_T status;
501
502 switch(operation)
503 {
504 case VC_CONTAINER_CONTROL_TRACK_ADD:
505 {
506 VC_CONTAINER_ES_FORMAT_T *p_format =
507 (VC_CONTAINER_ES_FORMAT_T *)va_arg( args, VC_CONTAINER_ES_FORMAT_T * );
508 return asf_writer_add_track(p_ctx, p_format);
509 }
510
511 case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
512 if(!module->b_header_done)
513 {
514 status = asf_write_header(p_ctx);
515 if(status != VC_CONTAINER_SUCCESS) return status;
516 module->b_header_done = true;
517 }
518 return VC_CONTAINER_SUCCESS;
519
520 default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
521 }
522}
523
524/******************************************************************************
525Global function definitions.
526******************************************************************************/
527
528VC_CONTAINER_STATUS_T asf_writer_open( VC_CONTAINER_T *p_ctx )
529{
530 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
531 const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
532 VC_CONTAINER_MODULE_T *module = 0;
533 unsigned int i;
534
535 /* Check if the user has specified a container */
536 vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
537
538 /* Check we're the right writer for this */
539 if(!extension)
540 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
541 if(strcasecmp(extension, "asf") && strcasecmp(extension, "wmv") &&
542 strcasecmp(extension, "wma"))
543 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
544
545 /* Allocate our context */
546 module = malloc(sizeof(*module));
547 if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
548 memset(module, 0, sizeof(*module));
549 p_ctx->priv->module = module;
550 p_ctx->tracks = module->tracks;
551
552 /* Create a null i/o writer to help us out in writing our data */
553 status = vc_container_writer_extraio_create_null(p_ctx, &module->null);
554 if(status != VC_CONTAINER_SUCCESS) goto error;
555
556 /* We'll only write the header once we've got all our tracks */
557
558 p_ctx->priv->pf_close = asf_writer_close;
559 p_ctx->priv->pf_write = asf_writer_write;
560 p_ctx->priv->pf_control = asf_writer_control;
561 return VC_CONTAINER_SUCCESS;
562
563 error:
564 LOG_DEBUG(p_ctx, "asf: error opening stream");
565 for(i = 0; i < ASF_TRACKS_MAX && p_ctx->tracks && p_ctx->tracks[i]; i++)
566 vc_container_free_track(p_ctx, p_ctx->tracks[i]);
567 free(module);
568 return status;
569}
570
571/********************************************************************************
572 Entrypoint function
573 ********************************************************************************/
574
575#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
576# pragma weak writer_open asf_writer_open
577#endif
578