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 <stdio.h> |
28 | #include <stdlib.h> |
29 | #include <stdarg.h> |
30 | #include <string.h> |
31 | |
32 | #include "containers/core/containers_private.h" |
33 | #include "containers/core/containers_io_helpers.h" |
34 | #include "containers/core/containers_utils.h" |
35 | #include "containers/core/containers_logging.h" |
36 | |
37 | #include "raw_video_common.h" |
38 | |
39 | /****************************************************************************** |
40 | Defines. |
41 | ******************************************************************************/ |
42 | |
43 | /****************************************************************************** |
44 | Type definitions |
45 | ******************************************************************************/ |
46 | typedef struct VC_CONTAINER_MODULE_T |
47 | { |
48 | VC_CONTAINER_TRACK_T *track; |
49 | bool yuv4mpeg2; |
50 | bool ; |
51 | bool non_standard; |
52 | |
53 | } VC_CONTAINER_MODULE_T; |
54 | |
55 | /****************************************************************************** |
56 | Function prototypes |
57 | ******************************************************************************/ |
58 | VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T * ); |
59 | |
60 | /****************************************************************************** |
61 | Local Functions |
62 | ******************************************************************************/ |
63 | static VC_CONTAINER_STATUS_T ( VC_CONTAINER_T *ctx ) |
64 | { |
65 | VC_CONTAINER_MODULE_T *module = ctx->priv->module; |
66 | unsigned int size; |
67 | char line[128]; |
68 | const char *id; |
69 | |
70 | size = snprintf(line, sizeof(line), "YUV4MPEG2 W%i H%i" , |
71 | ctx->tracks[0]->format->type->video.width, |
72 | ctx->tracks[0]->format->type->video.height); |
73 | if (size >= sizeof(line)) |
74 | return VC_CONTAINER_ERROR_OUT_OF_RESOURCES; |
75 | WRITE_BYTES(ctx, line, size); |
76 | |
77 | if (ctx->tracks[0]->format->type->video.frame_rate_num && |
78 | ctx->tracks[0]->format->type->video.frame_rate_den) |
79 | { |
80 | size = snprintf(line, sizeof(line), " F%i:%i" , |
81 | ctx->tracks[0]->format->type->video.frame_rate_num, |
82 | ctx->tracks[0]->format->type->video.frame_rate_den); |
83 | if (size >= sizeof(line)) |
84 | return VC_CONTAINER_ERROR_OUT_OF_RESOURCES; |
85 | WRITE_BYTES(ctx, line, size); |
86 | } |
87 | |
88 | if (ctx->tracks[0]->format->type->video.par_num && |
89 | ctx->tracks[0]->format->type->video.par_den) |
90 | { |
91 | size = snprintf(line, sizeof(line), " A%i:%i" , |
92 | ctx->tracks[0]->format->type->video.par_num, |
93 | ctx->tracks[0]->format->type->video.par_den); |
94 | if (size >= sizeof(line)) |
95 | return VC_CONTAINER_ERROR_OUT_OF_RESOURCES; |
96 | WRITE_BYTES(ctx, line, size); |
97 | } |
98 | |
99 | if (to_yuv4mpeg2(ctx->tracks[0]->format->codec, &id, 0, 0)) |
100 | { |
101 | size = snprintf(line, sizeof(line), " C%s" , id); |
102 | } |
103 | else |
104 | { |
105 | module->non_standard = true; |
106 | size = snprintf(line, sizeof(line), " C%4.4s" , |
107 | (char *)&ctx->tracks[0]->format->codec); |
108 | } |
109 | if (size >= sizeof(line)) |
110 | return VC_CONTAINER_ERROR_OUT_OF_RESOURCES; |
111 | WRITE_BYTES(ctx, line, size); |
112 | |
113 | _WRITE_U8(ctx, 0x0a); |
114 | module->header_done = true; |
115 | return STREAM_STATUS(ctx); |
116 | } |
117 | |
118 | static VC_CONTAINER_STATUS_T simple_write_add_track( VC_CONTAINER_T *ctx, |
119 | VC_CONTAINER_ES_FORMAT_T *format ) |
120 | { |
121 | VC_CONTAINER_STATUS_T status; |
122 | |
123 | /* Sanity check that we support the type of track being created */ |
124 | if (ctx->tracks_num) |
125 | return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION; |
126 | if (format->es_type != VC_CONTAINER_ES_TYPE_VIDEO) |
127 | return VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED; |
128 | |
129 | /* Allocate and initialise track data */ |
130 | ctx->tracks[0] = vc_container_allocate_track(ctx, 0); |
131 | if (!ctx->tracks[0]) |
132 | return VC_CONTAINER_ERROR_OUT_OF_MEMORY; |
133 | |
134 | status = vc_container_track_allocate_extradata(ctx, |
135 | ctx->tracks[0], format->extradata_size); |
136 | if(status != VC_CONTAINER_SUCCESS) |
137 | return status; |
138 | |
139 | vc_container_format_copy(ctx->tracks[0]->format, format, |
140 | format->extradata_size); |
141 | ctx->tracks_num++; |
142 | return VC_CONTAINER_SUCCESS; |
143 | } |
144 | |
145 | /***************************************************************************** |
146 | Functions exported as part of the Container Module API |
147 | *****************************************************************************/ |
148 | static VC_CONTAINER_STATUS_T rawvideo_writer_close( VC_CONTAINER_T *ctx ) |
149 | { |
150 | VC_CONTAINER_MODULE_T *module = ctx->priv->module; |
151 | for (; ctx->tracks_num > 0; ctx->tracks_num--) |
152 | vc_container_free_track(ctx, ctx->tracks[ctx->tracks_num-1]); |
153 | free(module); |
154 | return VC_CONTAINER_SUCCESS; |
155 | } |
156 | |
157 | /*****************************************************************************/ |
158 | static VC_CONTAINER_STATUS_T rawvideo_writer_write( VC_CONTAINER_T *ctx, |
159 | VC_CONTAINER_PACKET_T *packet ) |
160 | { |
161 | VC_CONTAINER_MODULE_T *module = ctx->priv->module; |
162 | VC_CONTAINER_STATUS_T status; |
163 | |
164 | if (module->yuv4mpeg2 && !module->header_done) |
165 | { |
166 | status = rawvideo_write_header(ctx); |
167 | if (status != VC_CONTAINER_SUCCESS) |
168 | return status; |
169 | } |
170 | |
171 | if (module->yuv4mpeg2 && |
172 | (packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_START)) |
173 | { |
174 | /* Write the metadata */ |
175 | WRITE_BYTES(ctx, "FRAME" , sizeof("FRAME" )-1); |
176 | |
177 | /* For formats not supported by the YUV4MPEG2 spec, we prepend |
178 | * each frame with its size */ |
179 | if (module->non_standard) |
180 | { |
181 | unsigned int size; |
182 | char line[32]; |
183 | size = snprintf(line, sizeof(line), " S%i" , |
184 | packet->frame_size ? packet->frame_size : packet->size); |
185 | if (size < sizeof(line)) |
186 | WRITE_BYTES(ctx, line, size); |
187 | } |
188 | |
189 | _WRITE_U8(ctx, 0x0a); |
190 | } |
191 | |
192 | /* Write the elementary stream */ |
193 | WRITE_BYTES(ctx, packet->data, packet->size); |
194 | |
195 | return STREAM_STATUS(ctx); |
196 | } |
197 | |
198 | /*****************************************************************************/ |
199 | static VC_CONTAINER_STATUS_T rawvideo_writer_control( VC_CONTAINER_T *ctx, |
200 | VC_CONTAINER_CONTROL_T operation, va_list args ) |
201 | { |
202 | VC_CONTAINER_MODULE_T *module = ctx->priv->module; |
203 | VC_CONTAINER_ES_FORMAT_T *format; |
204 | |
205 | switch (operation) |
206 | { |
207 | case VC_CONTAINER_CONTROL_TRACK_ADD: |
208 | format = (VC_CONTAINER_ES_FORMAT_T *)va_arg(args, VC_CONTAINER_ES_FORMAT_T *); |
209 | return simple_write_add_track(ctx, format); |
210 | |
211 | case VC_CONTAINER_CONTROL_TRACK_ADD_DONE: |
212 | return module->yuv4mpeg2 ? |
213 | rawvideo_write_header( ctx ) : VC_CONTAINER_SUCCESS; |
214 | |
215 | default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION; |
216 | } |
217 | } |
218 | |
219 | /*****************************************************************************/ |
220 | VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T *ctx ) |
221 | { |
222 | VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID; |
223 | const char *extension = vc_uri_path_extension(ctx->priv->uri); |
224 | VC_CONTAINER_MODULE_T *module; |
225 | bool yuv4mpeg2 = false; |
226 | |
227 | /* Check if the user has specified a container */ |
228 | vc_uri_find_query(ctx->priv->uri, 0, "container" , &extension); |
229 | |
230 | /* Check we're the right writer for this */ |
231 | if(!extension) |
232 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
233 | if(!strcasecmp(extension, "y4m" ) || !strcasecmp(extension, "yuv4mpeg2" )) |
234 | yuv4mpeg2 = true; |
235 | if(!yuv4mpeg2 && strcasecmp(extension, "yuv" )) |
236 | return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; |
237 | |
238 | LOG_DEBUG(ctx, "using rawvideo writer" ); |
239 | |
240 | /* Allocate our context */ |
241 | module = malloc(sizeof(*module)); |
242 | if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; } |
243 | memset(module, 0, sizeof(*module)); |
244 | ctx->priv->module = module; |
245 | ctx->tracks = &module->track; |
246 | module->yuv4mpeg2 = yuv4mpeg2; |
247 | |
248 | ctx->priv->pf_close = rawvideo_writer_close; |
249 | ctx->priv->pf_write = rawvideo_writer_write; |
250 | ctx->priv->pf_control = rawvideo_writer_control; |
251 | return VC_CONTAINER_SUCCESS; |
252 | |
253 | error: |
254 | LOG_DEBUG(ctx, "rawvideo: error opening stream (%i)" , status); |
255 | return status; |
256 | } |
257 | |
258 | /******************************************************************************** |
259 | Entrypoint function |
260 | ********************************************************************************/ |
261 | |
262 | #if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__) |
263 | # pragma weak writer_open rawvideo_writer_open |
264 | #endif |
265 | |