annotate trunk/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.cc @ 706:f8e90b5d85fd tip

Delete CARFAC code from this repository. It has been moved to https://github.com/google/carfac Please email me with your github username to get access. I've also created a new mailing list to discuss CARFAC development: https://groups.google.com/forum/#!forum/carfac-dev
author ronw@google.com
date Thu, 18 Jul 2013 20:56:51 +0000
parents dd13c9834ceb
children
rev   line source
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