comparison src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.cc @ 116:47b009f2c936

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