Mercurial > hg > aimc
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 } |