annotate src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovieDirect.cc @ 611:0fbaf443ec82

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