tomwalters@397
|
1 // Copyright 2007, Thomas Walters
|
tomwalters@397
|
2 //
|
tomwalters@397
|
3 // AIM-C: A C++ implementation of the Auditory Image Model
|
tomwalters@397
|
4 // http://www.acousticscale.org/AIMC
|
tomwalters@397
|
5 //
|
tomwalters@397
|
6 // Licensed under the Apache License, Version 2.0 (the "License");
|
tomwalters@397
|
7 // you may not use this file except in compliance with the License.
|
tomwalters@397
|
8 // You may obtain a copy of the License at
|
tomwalters@397
|
9 //
|
tomwalters@397
|
10 // http://www.apache.org/licenses/LICENSE-2.0
|
tomwalters@397
|
11 //
|
tomwalters@397
|
12 // Unless required by applicable law or agreed to in writing, software
|
tomwalters@397
|
13 // distributed under the License is distributed on an "AS IS" BASIS,
|
tomwalters@397
|
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
tomwalters@397
|
15 // See the License for the specific language governing permissions and
|
tomwalters@397
|
16 // limitations under the License.
|
tomwalters@397
|
17
|
tomwalters@397
|
18 /*!
|
tomwalters@397
|
19 * \file
|
tomwalters@397
|
20 * \brief Output device for output direct to a movie via local calls to libavcodec
|
tomwalters@397
|
21 *
|
tomwalters@397
|
22 * \author Tom Walters <tom@acousticscale.org>
|
tomwalters@397
|
23 * \date created 2007/10/05
|
tomwalters@397
|
24 * \version \$Id: $
|
tomwalters@397
|
25 */
|
tomwalters@397
|
26
|
tomwalters@397
|
27 #include "Support/Common.h"
|
tomwalters@397
|
28
|
tomwalters@397
|
29 #include <stdlib.h>
|
tomwalters@397
|
30 #include <stdio.h>
|
tomwalters@397
|
31 #include <string.h>
|
tomwalters@397
|
32 #include <math.h>
|
tomwalters@397
|
33
|
tom@400
|
34 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.h"
|
tom@400
|
35
|
tom@400
|
36 namespace aimc {
|
tomwalters@397
|
37
|
tomwalters@397
|
38 GraphicsOutputDeviceMovieDirect::GraphicsOutputDeviceMovieDirect(Parameters *params)
|
tomwalters@398
|
39 : GraphicsOutputDeviceMovie(params) {
|
tomwalters@398
|
40 m_sMovieFile[0] = '\0';
|
tomwalters@398
|
41 m_sSoundFile[0] = '\0';
|
tomwalters@397
|
42 }
|
tomwalters@397
|
43
|
tomwalters@397
|
44 bool GraphicsOutputDeviceMovieDirect::Initialize(const char *sSoundFile,
|
tomwalters@397
|
45 const char *sMovieFile) {
|
tomwalters@398
|
46 // We want pnm for direct movie conversion as the data format is nice and simple
|
tomwalters@398
|
47 //! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt
|
tomwalters@398
|
48 //m_pParam->SetString("output.img.format", "pnm");
|
tomwalters@397
|
49
|
tomwalters@398
|
50 // Initialise GraphicsOutputDevicePlotutils for memory buffer use
|
tomwalters@398
|
51 if(!GraphicsOutputDeviceCairo::Initialize())
|
tomwalters@397
|
52 return false;
|
tomwalters@397
|
53
|
tomwalters@397
|
54 int width = m_pParam->GetUInt("output.img.width");
|
tomwalters@398
|
55 int height = m_pParam->GetUInt("output.img.height");
|
tomwalters@398
|
56 //float framerate = 1000.0f/m_pParam->GetFloat("output.frameperiod");
|
tomwalters@398
|
57 float framerate=1000.0f/20.0f;
|
tomwalters@397
|
58
|
tomwalters@397
|
59 m_pOutputMovie = new LibavformatWriter;
|
tomwalters@398
|
60 m_pOutputMovie->Init(sMovieFile, width, height, framerate);
|
tomwalters@397
|
61
|
tomwalters@398
|
62 return true;
|
tomwalters@397
|
63 }
|
tomwalters@397
|
64
|
tomwalters@397
|
65 void GraphicsOutputDeviceMovieDirect::Stop() {
|
tomwalters@398
|
66 // Make sure Plotutils is really done writing.
|
tomwalters@398
|
67 GraphicsOutputDeviceCairo::Stop();
|
tomwalters@398
|
68 m_pOutputMovie->End();
|
tomwalters@398
|
69 delete m_pOutputMovie;
|
tomwalters@397
|
70
|
tomwalters@397
|
71 }
|
tomwalters@397
|
72
|
tomwalters@397
|
73 void GraphicsOutputDeviceMovieDirect::gRelease() {
|
tomwalters@397
|
74 // write the buffer
|
tomwalters@397
|
75 unsigned char *buf = GraphicsOutputDeviceCairo::GetBuffer();
|
tomwalters@397
|
76
|
tomwalters@397
|
77 if (buf != NULL)
|
tomwalters@397
|
78 m_pOutputMovie->WriteFrame(buf);
|
tomwalters@397
|
79
|
tomwalters@397
|
80 GraphicsOutputDeviceCairo::gRelease();
|
tomwalters@397
|
81 }
|
tomwalters@397
|
82
|
tomwalters@397
|
83
|
tomwalters@397
|
84 // Everything below here is hacked from the Libavformat API example:
|
tomwalters@397
|
85 /*
|
tomwalters@397
|
86 * Libavformat API example: Output a media file in any supported
|
tomwalters@397
|
87 * libavformat format. The default codecs are used.
|
tomwalters@397
|
88 *
|
tomwalters@397
|
89 * Copyright (c) 2003 Fabrice Bellard
|
tomwalters@397
|
90 *
|
tomwalters@397
|
91 * Permission is hereby granted, free of charge, to any person obtaining a copy
|
tomwalters@397
|
92 * of this software and associated documentation files (the "Software"), to deal
|
tomwalters@397
|
93 * in the Software without restriction, including without limitation the rights
|
tomwalters@397
|
94 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
tomwalters@397
|
95 * copies of the Software, and to permit persons to whom the Software is
|
tomwalters@397
|
96 * furnished to do so, subject to the following conditions:
|
tomwalters@397
|
97 *
|
tomwalters@397
|
98 * The above copyright notice and this permission notice shall be included in
|
tomwalters@397
|
99 * all copies or substantial portions of the Software.
|
tomwalters@397
|
100 *
|
tomwalters@397
|
101 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
tomwalters@397
|
102 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
tomwalters@397
|
103 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
tomwalters@397
|
104 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
tomwalters@397
|
105 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
tomwalters@397
|
106 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
tomwalters@397
|
107 * THE SOFTWARE.
|
tomwalters@397
|
108 */
|
tomwalters@397
|
109
|
tomwalters@397
|
110
|
tomwalters@397
|
111 LibavformatWriter::LibavformatWriter() {
|
tomwalters@397
|
112 sws_flags = SWS_BICUBIC;
|
tomwalters@397
|
113 pixfmt= PIX_FMT_RGB24;
|
tomwalters@397
|
114 fmt = NULL;
|
tomwalters@397
|
115 }
|
tomwalters@397
|
116
|
tomwalters@397
|
117 bool LibavformatWriter::Init(const char *sMovieFile,
|
tomwalters@397
|
118 int width,
|
tomwalters@397
|
119 int height,
|
tomwalters@397
|
120 float framerate) {
|
tomwalters@397
|
121 /* initialize libavcodec, and register all codecs and formats */
|
tomwalters@397
|
122 av_register_all();
|
tomwalters@397
|
123
|
tomwalters@397
|
124 /* auto detect the output format from the name. default is mpeg. */
|
tomwalters@397
|
125 fmt = guess_format(NULL, sMovieFile, NULL);
|
tomwalters@397
|
126 if (!fmt) {
|
tomwalters@397
|
127 printf("Could not deduce output format from file extension: using MPEG.\n");
|
tomwalters@397
|
128 fmt = guess_format("mpeg", NULL, NULL);
|
tomwalters@397
|
129 }
|
tomwalters@397
|
130 if (!fmt) {
|
tomwalters@397
|
131 fprintf(stderr, "Could not find suitable output format\n");
|
tomwalters@397
|
132 return false;
|
tomwalters@397
|
133 }
|
tomwalters@397
|
134
|
tomwalters@397
|
135 /* allocate the output media context */
|
tomwalters@397
|
136 oc = av_alloc_format_context();
|
tomwalters@397
|
137 if (!oc) {
|
tomwalters@397
|
138 fprintf(stderr, "Memory error\n");
|
tomwalters@397
|
139 return false;
|
tomwalters@397
|
140 }
|
tomwalters@397
|
141 oc->oformat = fmt;
|
tomwalters@397
|
142 snprintf(oc->filename, sizeof(oc->filename), "%s", sMovieFile);
|
tomwalters@397
|
143
|
tomwalters@397
|
144 /* add the audio and video streams using the default format codecs
|
tomwalters@397
|
145 and initialize the codecs */
|
tomwalters@397
|
146 video_st = NULL;
|
tomwalters@397
|
147 fmt->video_codec=CODEC_ID_PNG;
|
tomwalters@397
|
148 if (fmt->video_codec != CODEC_ID_NONE) {
|
tomwalters@397
|
149 video_st = add_video_stream(oc, fmt->video_codec, width, height, framerate);
|
tomwalters@397
|
150 }
|
tomwalters@397
|
151
|
tomwalters@397
|
152 /* set the output parameters (must be done even if no
|
tomwalters@397
|
153 parameters). */
|
tomwalters@397
|
154 if (av_set_parameters(oc, NULL) < 0) {
|
tomwalters@397
|
155 fprintf(stderr, "Invalid output format parameters\n");
|
tomwalters@397
|
156 return false;
|
tomwalters@397
|
157 }
|
tomwalters@397
|
158
|
tomwalters@397
|
159 dump_format(oc, 0, sMovieFile, 1);
|
tomwalters@397
|
160
|
tomwalters@397
|
161 /* now that all the parameters are set, we can open the audio and
|
tomwalters@397
|
162 video codecs and allocate the necessary encode buffers */
|
tomwalters@397
|
163 if (video_st) {
|
tomwalters@397
|
164 open_video(oc, video_st);
|
tomwalters@397
|
165 }
|
tomwalters@397
|
166
|
tomwalters@397
|
167 /* open the output file, if needed */
|
tomwalters@397
|
168 if (!(fmt->flags & AVFMT_NOFILE)) {
|
tomwalters@397
|
169 if (url_fopen(&oc->pb, sMovieFile, URL_WRONLY) < 0) {
|
tomwalters@397
|
170 fprintf(stderr, "Could not open '%s'\n", sMovieFile);
|
tomwalters@397
|
171 return false;
|
tomwalters@397
|
172 }
|
tomwalters@397
|
173 }
|
tomwalters@397
|
174
|
tomwalters@397
|
175 /* write the stream header, if any */
|
tomwalters@397
|
176 av_write_header(oc);
|
tomwalters@397
|
177 return true;
|
tomwalters@397
|
178 }
|
tomwalters@397
|
179
|
tomwalters@397
|
180
|
tomwalters@397
|
181 /**************************************************************/
|
tomwalters@397
|
182 /* video output */
|
tomwalters@397
|
183
|
tomwalters@397
|
184 /* add a video output stream */
|
tomwalters@397
|
185 AVStream* LibavformatWriter::add_video_stream(AVFormatContext *oc,
|
tomwalters@397
|
186 CodecID codec_id,
|
tomwalters@397
|
187 int width,
|
tomwalters@397
|
188 int height,
|
tomwalters@397
|
189 float framerate) {
|
tomwalters@397
|
190 AVCodecContext *c;
|
tomwalters@397
|
191 AVStream *st;
|
tomwalters@397
|
192
|
tomwalters@397
|
193 st = av_new_stream(oc, 0);
|
tomwalters@397
|
194 if (!st) {
|
tomwalters@397
|
195 fprintf(stderr, "Could not alloc stream\n");
|
tomwalters@397
|
196 return NULL;
|
tomwalters@397
|
197 }
|
tomwalters@397
|
198
|
tomwalters@397
|
199 c = st->codec;
|
tomwalters@397
|
200 c->codec_id = codec_id;
|
tomwalters@397
|
201 c->codec_type = CODEC_TYPE_VIDEO;
|
tomwalters@397
|
202
|
tomwalters@397
|
203 /* put sample parameters */
|
tomwalters@397
|
204 /* resolution must be a multiple of two */
|
tomwalters@397
|
205 c->width = width;
|
tomwalters@397
|
206 c->height = height;
|
tomwalters@397
|
207 /* time base: this is the fundamental unit of time (in seconds) in terms
|
tomwalters@397
|
208 of which frame timestamps are represented. for fixed-fps content,
|
tomwalters@397
|
209 timebase should be 1/framerate and timestamp increments should be
|
tomwalters@397
|
210 identically 1. */
|
tomwalters@397
|
211 c->time_base.den = (int)framerate;
|
tomwalters@397
|
212 c->time_base.num = 1;
|
tomwalters@397
|
213 c->gop_size = 12; /* emit one intra frame every twelve frames at most */
|
tomwalters@397
|
214 c->pix_fmt = pixfmt;
|
tomwalters@397
|
215 // some formats want stream headers to be separate
|
tomwalters@397
|
216 if(!strcmp(oc->oformat->name, "mp4")
|
tomwalters@397
|
217 || !strcmp(oc->oformat->name, "mov")
|
tomwalters@397
|
218 || !strcmp(oc->oformat->name, "3gp")) {
|
tomwalters@397
|
219 c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
tomwalters@397
|
220 }
|
tomwalters@397
|
221 return st;
|
tomwalters@397
|
222 }
|
tomwalters@397
|
223
|
tomwalters@397
|
224 AVFrame* LibavformatWriter::alloc_picture(int pix_fmt,
|
tomwalters@397
|
225 int width,
|
tomwalters@397
|
226 int height) {
|
tomwalters@397
|
227 AVFrame *picture;
|
tomwalters@397
|
228 uint8_t *picture_buf;
|
tomwalters@397
|
229 int size;
|
tomwalters@397
|
230
|
tomwalters@397
|
231 picture = avcodec_alloc_frame();
|
tomwalters@397
|
232 if (!picture) {
|
tomwalters@397
|
233 return NULL;
|
tomwalters@397
|
234 }
|
tomwalters@397
|
235 size = avpicture_get_size(pix_fmt, width, height);
|
tomwalters@397
|
236 picture_buf = (uint8_t*)av_malloc(size);
|
tomwalters@397
|
237 if (!picture_buf) {
|
tomwalters@397
|
238 av_free(picture);
|
tomwalters@397
|
239 return NULL;
|
tomwalters@397
|
240 }
|
tomwalters@397
|
241 avpicture_fill((AVPicture *)picture, picture_buf,
|
tomwalters@397
|
242 pix_fmt, width, height);
|
tomwalters@397
|
243 return picture;
|
tomwalters@397
|
244 }
|
tomwalters@397
|
245
|
tomwalters@397
|
246 void LibavformatWriter::open_video(AVFormatContext *oc, AVStream *st) {
|
tomwalters@397
|
247 AVCodec *codec;
|
tomwalters@397
|
248 AVCodecContext *c;
|
tomwalters@397
|
249 c = st->codec;
|
tomwalters@397
|
250
|
tomwalters@397
|
251 /* find the video encoder */
|
tomwalters@397
|
252 codec = avcodec_find_encoder(c->codec_id);
|
tomwalters@397
|
253 if (!codec) {
|
tomwalters@397
|
254 fprintf(stderr, "codec not found\n");
|
tomwalters@397
|
255 exit(1);
|
tomwalters@397
|
256 }
|
tomwalters@397
|
257
|
tomwalters@397
|
258 /* open the codec */
|
tomwalters@397
|
259 if (avcodec_open(c, codec) < 0) {
|
tomwalters@397
|
260 fprintf(stderr, "could not open codec\n");
|
tomwalters@397
|
261 exit(1);
|
tomwalters@397
|
262 }
|
tomwalters@397
|
263
|
tomwalters@397
|
264 video_outbuf = NULL;
|
tomwalters@397
|
265 if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
|
tomwalters@397
|
266 /* allocate output buffer */
|
tomwalters@397
|
267 /* XXX: API change will be done */
|
tomwalters@397
|
268 /* buffers passed into lav* can be allocated any way you prefer,
|
tomwalters@397
|
269 as long as they're aligned enough for the architecture, and
|
tomwalters@397
|
270 they're freed appropriately (such as using av_free for buffers
|
tomwalters@397
|
271 allocated with av_malloc) */
|
tomwalters@397
|
272 video_outbuf_size = 200000;
|
tomwalters@397
|
273 video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
|
tomwalters@397
|
274 }
|
tomwalters@397
|
275
|
tomwalters@397
|
276 /* allocate the encoded raw picture */
|
tomwalters@397
|
277 picture = alloc_picture(c->pix_fmt, c->width, c->height);
|
tomwalters@397
|
278 if (!picture) {
|
tomwalters@397
|
279 fprintf(stderr, "Could not allocate picture\n");
|
tomwalters@397
|
280 exit(1);
|
tomwalters@397
|
281 }
|
tomwalters@397
|
282
|
tomwalters@397
|
283 /* if the output format is not RGB32, then a temporary RGB32
|
tomwalters@397
|
284 picture is needed too. It is then converted to the required
|
tomwalters@397
|
285 output format */
|
tomwalters@397
|
286 tmp_picture = NULL;
|
tomwalters@397
|
287 if (c->pix_fmt != PIX_FMT_RGB32) {
|
tomwalters@397
|
288 tmp_picture = alloc_picture(PIX_FMT_RGB32, c->width, c->height);
|
tomwalters@397
|
289 if (!tmp_picture) {
|
tomwalters@397
|
290 fprintf(stderr, "Could not allocate temporary picture\n");
|
tomwalters@397
|
291 exit(1);
|
tomwalters@397
|
292 }
|
tomwalters@397
|
293 }
|
tomwalters@397
|
294 }
|
tomwalters@397
|
295
|
tomwalters@397
|
296
|
tomwalters@397
|
297 void LibavformatWriter::close_video(AVFormatContext *oc,
|
tomwalters@397
|
298 AVStream *st) {
|
tomwalters@397
|
299 avcodec_close(st->codec);
|
tomwalters@397
|
300 av_free(picture->data[0]);
|
tomwalters@397
|
301 av_free(picture);
|
tomwalters@397
|
302 if (tmp_picture) {
|
tomwalters@397
|
303 av_free(tmp_picture->data[0]);
|
tomwalters@397
|
304 av_free(tmp_picture);
|
tomwalters@397
|
305 }
|
tomwalters@397
|
306 av_free(video_outbuf);
|
tomwalters@397
|
307 }
|
tomwalters@397
|
308
|
tomwalters@397
|
309 void LibavformatWriter::WriteFrame(unsigned char *pFrameBuffer) {
|
tomwalters@397
|
310 /* compute current video time */
|
tomwalters@397
|
311 if (video_st)
|
tomwalters@397
|
312 video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
|
tomwalters@397
|
313 else
|
tomwalters@397
|
314 video_pts = 0.0;
|
tomwalters@397
|
315
|
tomwalters@397
|
316 int out_size, ret;
|
tomwalters@397
|
317 AVCodecContext *c;
|
tomwalters@397
|
318 static struct SwsContext *img_convert_ctx;
|
tomwalters@397
|
319 c = video_st->codec;
|
tomwalters@397
|
320 if (c->pix_fmt != PIX_FMT_RGB32) {
|
tomwalters@397
|
321 /* as we only generate a RGB32 picture, we must convert it
|
tomwalters@397
|
322 to the codec pixel format if needed */
|
tomwalters@397
|
323 if (img_convert_ctx == NULL) {
|
tomwalters@397
|
324 img_convert_ctx = sws_getContext(c->width,
|
tomwalters@397
|
325 c->height,
|
tomwalters@397
|
326 PIX_FMT_RGB32,
|
tomwalters@397
|
327 c->width,
|
tomwalters@397
|
328 c->height,
|
tomwalters@397
|
329 c->pix_fmt,
|
tomwalters@397
|
330 sws_flags,
|
tomwalters@397
|
331 NULL,
|
tomwalters@397
|
332 NULL,
|
tomwalters@397
|
333 NULL);
|
tomwalters@397
|
334 if (img_convert_ctx == NULL) {
|
tomwalters@397
|
335 fprintf(stderr, "Cannot initialize the conversion context\n");
|
tomwalters@397
|
336 exit(1);
|
tomwalters@397
|
337 }
|
tomwalters@397
|
338 }
|
tomwalters@397
|
339 fill_image(tmp_picture, pFrameBuffer, c->width, c->height);
|
tomwalters@397
|
340 sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize,
|
tomwalters@397
|
341 0, c->height, picture->data, picture->linesize);
|
tomwalters@397
|
342 } else {
|
tomwalters@397
|
343 fill_image(picture, pFrameBuffer, c->width, c->height);
|
tomwalters@397
|
344 }
|
tomwalters@397
|
345 /* encode the image */
|
tomwalters@397
|
346 out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
|
tomwalters@397
|
347 /* if zero size, it means the image was buffered */
|
tomwalters@397
|
348 if (out_size > 0) {
|
tomwalters@397
|
349 AVPacket pkt;
|
tomwalters@397
|
350 av_init_packet(&pkt);
|
tomwalters@397
|
351
|
tomwalters@397
|
352 pkt.pts= av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base);
|
tomwalters@397
|
353 if(c->coded_frame->key_frame) {
|
tomwalters@397
|
354 pkt.flags |= PKT_FLAG_KEY;
|
tomwalters@397
|
355 pkt.stream_index= video_st->index;
|
tomwalters@397
|
356 pkt.data= video_outbuf;
|
tomwalters@397
|
357 pkt.size= out_size;
|
tomwalters@397
|
358 /* write the compressed frame in the media file */
|
tomwalters@397
|
359 ret = av_write_frame(oc, &pkt);
|
tomwalters@397
|
360 }
|
tomwalters@397
|
361 } else {
|
tomwalters@397
|
362 ret = 0;
|
tomwalters@397
|
363 }
|
tomwalters@397
|
364 if (ret != 0) {
|
tomwalters@397
|
365 fprintf(stderr, "Error while writing video frame\n");
|
tomwalters@397
|
366 exit(1);
|
tomwalters@397
|
367 }
|
tomwalters@397
|
368 }
|
tomwalters@397
|
369
|
tomwalters@397
|
370 void LibavformatWriter::End() {
|
tomwalters@397
|
371 /* close each codec */
|
tomwalters@397
|
372 if (video_st) {
|
tomwalters@397
|
373 close_video(oc, video_st);
|
tomwalters@397
|
374 }
|
tomwalters@397
|
375 /* write the trailer, if any */
|
tomwalters@397
|
376 av_write_trailer(oc);
|
tomwalters@397
|
377
|
tomwalters@397
|
378 /* free the streams */
|
tomwalters@397
|
379 for(i = 0; i < oc->nb_streams; i++) {
|
tomwalters@397
|
380 av_freep(&oc->streams[i]->codec);
|
tomwalters@397
|
381 av_freep(&oc->streams[i]);
|
tomwalters@397
|
382 }
|
tomwalters@397
|
383
|
tomwalters@397
|
384 if (!(fmt->flags & AVFMT_NOFILE)) {
|
tomwalters@397
|
385 /* close the output file */
|
tomwalters@397
|
386 url_fclose(&oc->pb);
|
tomwalters@397
|
387 }
|
tomwalters@397
|
388 /* free the stream */
|
tomwalters@397
|
389 av_free(oc);
|
tomwalters@397
|
390 }
|
tomwalters@397
|
391
|
tomwalters@397
|
392 void LibavformatWriter::fill_image(AVFrame *pict,
|
tomwalters@397
|
393 unsigned char *pFrameBuffer,
|
tomwalters@397
|
394 int width,
|
tomwalters@397
|
395 int height) {
|
tomwalters@398
|
396 memcpy((void*)&(pict->data[0][0]), (void*)pFrameBuffer, width*height*4);
|
tomwalters@397
|
397 }
|
tom@400
|
398 } // namespace aimc
|