forked from 0ad/0ad
Remove unused VideoRecorder from Atlas.
This was SVN commit r14181.
This commit is contained in:
parent
d459e97d33
commit
47b26e56d3
@ -1,448 +0,0 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
|
||||||
* This file is part of 0 A.D.
|
|
||||||
*
|
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* 0 A.D. is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "precompiled.h"
|
|
||||||
|
|
||||||
#define USE_FFMPEG 0
|
|
||||||
|
|
||||||
#include "FFmpeg.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Code originally taken from ffmpeg's output_example.c
|
|
||||||
This is all rather hacked together and unreliable. In particular, I should:
|
|
||||||
* Change the fprintf/exit error handling so that it works in Atlas.
|
|
||||||
* Send all the logging output to wx too.
|
|
||||||
* Support variable bitrate (set qscale to 1 (best) .. 31 (worst), sameq)
|
|
||||||
* See if other codecs (particularly lossless ones) could be made to work.
|
|
||||||
(Currently it half assumes that it's passed a .mp4 filename.)
|
|
||||||
* See if other compression parameters would give better quality/speed/etc.
|
|
||||||
* Make the frame size variable.
|
|
||||||
* Tidy everything up a bit.
|
|
||||||
|
|
||||||
Please complain if I forget to do those things.
|
|
||||||
|
|
||||||
*/
|
|
||||||
#if USE_FFMPEG
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
// ugly hack to make recent versions of FFmpeg work
|
|
||||||
#define __STDC_CONSTANT_MACROS
|
|
||||||
#undef _STDINT_H
|
|
||||||
#undef _STDINT_H_
|
|
||||||
#include <stdint.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "FFmpeg.h"
|
|
||||||
#if _MSC_VER // HACK
|
|
||||||
#define vsnprintf _vsnprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning(disable: 4100 4505 4510 4610)
|
|
||||||
// Doesn't have inttypes.h, so cheat before including the ffmpeg headers
|
|
||||||
typedef unsigned __int8 uint8_t;
|
|
||||||
typedef unsigned __int16 uint16_t;
|
|
||||||
typedef unsigned __int32 uint32_t;
|
|
||||||
typedef unsigned __int64 uint64_t;
|
|
||||||
typedef __int8 int8_t;
|
|
||||||
typedef __int16 int16_t;
|
|
||||||
typedef __int32 int32_t;
|
|
||||||
typedef __int64 int64_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define WXUNUSED(arg)
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "ffmpeg/avformat.h"
|
|
||||||
#include "ffmpeg/swscale.h"
|
|
||||||
}
|
|
||||||
// (Have to use a sufficiently recent version to get swscale - it needs the ~x86 keyword on Gentoo)
|
|
||||||
|
|
||||||
struct VideoEncoderImpl
|
|
||||||
{
|
|
||||||
int framerate;
|
|
||||||
int bitrate;
|
|
||||||
float duration;
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
AVStream *video_st;
|
|
||||||
AVFormatContext *oc;
|
|
||||||
AVOutputFormat *fmt;
|
|
||||||
|
|
||||||
AVFrame *picture, *tmp_picture;
|
|
||||||
uint8_t *video_outbuf;
|
|
||||||
int frame_count, video_outbuf_size;
|
|
||||||
|
|
||||||
VideoEncoderImpl()
|
|
||||||
{
|
|
||||||
video_st = NULL;
|
|
||||||
oc = NULL;
|
|
||||||
fmt = NULL;
|
|
||||||
|
|
||||||
picture = NULL;
|
|
||||||
tmp_picture = NULL;
|
|
||||||
video_outbuf = NULL;
|
|
||||||
frame_count = 0;
|
|
||||||
video_outbuf_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AVStream *add_video_stream(AVFormatContext *oc, int codec_id)
|
|
||||||
{
|
|
||||||
AVCodecContext *c;
|
|
||||||
AVStream *st;
|
|
||||||
|
|
||||||
st = av_new_stream(oc, 0);
|
|
||||||
if (!st) {
|
|
||||||
fprintf(stderr, "Could not alloc stream\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
c = st->codec;
|
|
||||||
c->codec_id = (CodecID)codec_id;
|
|
||||||
c->codec_type = CODEC_TYPE_VIDEO;
|
|
||||||
|
|
||||||
// c->bit_rate = bitrate*1000;
|
|
||||||
// TODO: support compressed formats, using qscale
|
|
||||||
|
|
||||||
c->width = width;
|
|
||||||
c->height = height;
|
|
||||||
|
|
||||||
c->time_base.den = framerate;
|
|
||||||
c->time_base.num = 1;
|
|
||||||
|
|
||||||
// c->pix_fmt = PIX_FMT_YUV420P;
|
|
||||||
c->pix_fmt = PIX_FMT_RGBA32;
|
|
||||||
|
|
||||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
|
|
||||||
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
|
||||||
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
AVFrame *alloc_picture(int pix_fmt, int width, int height)
|
|
||||||
{
|
|
||||||
AVFrame *picture;
|
|
||||||
uint8_t *picture_buf;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
picture = avcodec_alloc_frame();
|
|
||||||
if (!picture)
|
|
||||||
return NULL;
|
|
||||||
size = avpicture_get_size(pix_fmt, width, height);
|
|
||||||
picture_buf = (uint8_t*)av_malloc(size);
|
|
||||||
if (!picture_buf) {
|
|
||||||
av_free(picture);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
avpicture_fill((AVPicture *)picture, picture_buf,
|
|
||||||
pix_fmt, width, height);
|
|
||||||
return picture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void open_video(AVFormatContext *oc, AVStream *st)
|
|
||||||
{
|
|
||||||
AVCodec *codec;
|
|
||||||
AVCodecContext *c;
|
|
||||||
|
|
||||||
c = st->codec;
|
|
||||||
|
|
||||||
/* find the video encoder */
|
|
||||||
codec = avcodec_find_encoder(c->codec_id);
|
|
||||||
if (!codec) {
|
|
||||||
fprintf(stderr, "codec not found\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open the codec */
|
|
||||||
if (avcodec_open(c, codec) < 0) {
|
|
||||||
fprintf(stderr, "could not open codec\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
video_outbuf = NULL;
|
|
||||||
if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
|
|
||||||
/* allocate output buffer */
|
|
||||||
/* XXX: API change will be done */
|
|
||||||
/* buffers passed into lav* can be allocated any way you prefer,
|
|
||||||
as long as they're aligned enough for the architecture, and
|
|
||||||
they're freed appropriately (such as using av_free for buffers
|
|
||||||
allocated with av_malloc) */
|
|
||||||
video_outbuf_size = c->width * c->height * 4;
|
|
||||||
video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate the encoded raw picture */
|
|
||||||
picture = alloc_picture(c->pix_fmt, c->width, c->height);
|
|
||||||
if (!picture) {
|
|
||||||
fprintf(stderr, "Could not allocate picture\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the output format is not YUV420P, then a temporary YUV420P
|
|
||||||
picture is needed too. It is then converted to the required
|
|
||||||
output format */
|
|
||||||
tmp_picture = NULL;
|
|
||||||
if (c->pix_fmt != PIX_FMT_RGB24) {
|
|
||||||
tmp_picture = alloc_picture(PIX_FMT_RGB24, c->width, c->height);
|
|
||||||
if (!tmp_picture) {
|
|
||||||
fprintf(stderr, "Could not allocate temporary picture\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_rgb_image(AVFrame *pict, int width, int height, const unsigned char* buffer)
|
|
||||||
{
|
|
||||||
for(int y=0;y<height;y++) {
|
|
||||||
memcpy(&pict->data[0][y * pict->linesize[0]], buffer+y*width*3, width*3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_video_frame(AVFormatContext *oc, AVStream *st, const unsigned char* buffer)
|
|
||||||
{
|
|
||||||
AVCodecContext *c;
|
|
||||||
static struct SwsContext *img_convert_ctx;
|
|
||||||
int out_size, ret;
|
|
||||||
|
|
||||||
c = st->codec;
|
|
||||||
|
|
||||||
if (!buffer || frame_count >= (int)(duration*framerate)) {
|
|
||||||
/* no more frame to compress. The codec has a latency of a few
|
|
||||||
frames if using B frames, so we get the last frames by
|
|
||||||
passing the same picture again */
|
|
||||||
} else {
|
|
||||||
if (c->pix_fmt != PIX_FMT_RGB24) {
|
|
||||||
/* as we only generate a YUV420P picture, we must convert it
|
|
||||||
to the codec pixel format if needed */
|
|
||||||
if (img_convert_ctx == NULL) {
|
|
||||||
img_convert_ctx = sws_getContext(c->width, c->height,
|
|
||||||
PIX_FMT_RGB24,
|
|
||||||
c->width, c->height,
|
|
||||||
c->pix_fmt,
|
|
||||||
SWS_BICUBIC, NULL, NULL, NULL);
|
|
||||||
if (img_convert_ctx == NULL) {
|
|
||||||
fprintf(stderr, "Cannot initialize the conversion context\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
copy_rgb_image(tmp_picture, c->width, c->height, buffer);
|
|
||||||
sws_scale(img_convert_ctx, tmp_picture->data, tmp_picture->linesize,
|
|
||||||
0, c->height, picture->data, picture->linesize);
|
|
||||||
} else {
|
|
||||||
copy_rgb_image(picture, c->width, c->height, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oc->oformat->flags & AVFMT_RAWPICTURE) {
|
|
||||||
/* raw video case. The API will change slightly in the near
|
|
||||||
future for that */
|
|
||||||
AVPacket pkt;
|
|
||||||
av_init_packet(&pkt);
|
|
||||||
|
|
||||||
pkt.flags |= PKT_FLAG_KEY;
|
|
||||||
pkt.stream_index= st->index;
|
|
||||||
pkt.data= (uint8_t *)picture;
|
|
||||||
pkt.size= sizeof(AVPicture);
|
|
||||||
|
|
||||||
ret = av_write_frame(oc, &pkt);
|
|
||||||
} else {
|
|
||||||
/* encode the image */
|
|
||||||
out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture);
|
|
||||||
/* if zero size, it means the image was buffered */
|
|
||||||
if (out_size > 0) {
|
|
||||||
AVPacket pkt;
|
|
||||||
av_init_packet(&pkt);
|
|
||||||
|
|
||||||
if (c->coded_frame->pts == AV_NOPTS_VALUE)
|
|
||||||
pkt.pts = AV_NOPTS_VALUE;
|
|
||||||
else
|
|
||||||
pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
|
|
||||||
if(c->coded_frame->key_frame)
|
|
||||||
pkt.flags |= PKT_FLAG_KEY;
|
|
||||||
pkt.stream_index= st->index;
|
|
||||||
pkt.data= video_outbuf;
|
|
||||||
pkt.size= out_size;
|
|
||||||
|
|
||||||
/* write the compressed frame in the media file */
|
|
||||||
ret = av_write_frame(oc, &pkt);
|
|
||||||
} else {
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ret != 0) {
|
|
||||||
fprintf(stderr, "Error while writing video frame\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
frame_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close_video(AVFormatContext *WXUNUSED(oc), AVStream *st)
|
|
||||||
{
|
|
||||||
avcodec_close(st->codec);
|
|
||||||
av_free(picture->data[0]);
|
|
||||||
av_free(picture);
|
|
||||||
if (tmp_picture) {
|
|
||||||
av_free(tmp_picture->data[0]);
|
|
||||||
av_free(tmp_picture);
|
|
||||||
}
|
|
||||||
av_free(video_outbuf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void log(void* WXUNUSED(v), int i, const char* format, va_list ap)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
vsnprintf(buf, sizeof(buf), format, ap);
|
|
||||||
buf[sizeof(buf)-1] = '\0';
|
|
||||||
wxLogDebug(L"[%d] %hs", i, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoEncoder::VideoEncoder(const wxString& filenameStr, int framerate, int bitrate, float duration, int width, int height)
|
|
||||||
: m(new VideoEncoderImpl)
|
|
||||||
{
|
|
||||||
wxCharBuffer filename = filenameStr.ToAscii();
|
|
||||||
m->framerate = framerate;
|
|
||||||
m->bitrate = bitrate;
|
|
||||||
m->duration = duration;
|
|
||||||
m->width = width;
|
|
||||||
m->height = height;
|
|
||||||
|
|
||||||
/* initialize libavcodec, and register all codecs and formats */
|
|
||||||
av_register_all();
|
|
||||||
|
|
||||||
av_log_set_callback(&log);
|
|
||||||
|
|
||||||
/* auto detect the output format from the name. default is mpeg. */
|
|
||||||
m->fmt = guess_format(NULL, filename, NULL);
|
|
||||||
if (!m->fmt) {
|
|
||||||
fprintf(stderr, "Could not deduce output format from file extension: using MPEG.\n");
|
|
||||||
m->fmt = guess_format("mpeg", NULL, NULL);
|
|
||||||
}
|
|
||||||
if (!m->fmt) {
|
|
||||||
fprintf(stderr, "Could not find suitable output format\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate the output media context */
|
|
||||||
m->oc = av_alloc_format_context();
|
|
||||||
if (!m->oc) {
|
|
||||||
fprintf(stderr, "Memory error\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
m->oc->oformat = m->fmt;
|
|
||||||
strncpy(m->oc->filename, filename, sizeof(m->oc->filename));
|
|
||||||
m->oc->filename[sizeof(m->oc->filename) - 1] = '\0';
|
|
||||||
|
|
||||||
/* add the audio and video streams using the default format codecs
|
|
||||||
and initialize the codecs */
|
|
||||||
// m->video_st = NULL;
|
|
||||||
// if (m->fmt->video_codec != CODEC_ID_NONE) {
|
|
||||||
// m->video_st = m->add_video_stream(m->oc, m->fmt->video_codec);
|
|
||||||
// }
|
|
||||||
m->video_st = m->add_video_stream(m->oc, CODEC_ID_FFV1);
|
|
||||||
|
|
||||||
/* set the output parameters (must be done even if no
|
|
||||||
parameters). */
|
|
||||||
if (av_set_parameters(m->oc, NULL) < 0) {
|
|
||||||
fprintf(stderr, "Invalid output format parameters\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
dump_format(m->oc, 0, filename, 1);
|
|
||||||
|
|
||||||
/* now that all the parameters are set, we can open the audio and
|
|
||||||
video codecs and allocate the necessary encode buffers */
|
|
||||||
if (m->video_st)
|
|
||||||
m->open_video(m->oc, m->video_st);
|
|
||||||
|
|
||||||
/* open the output file, if needed */
|
|
||||||
if (!(m->fmt->flags & AVFMT_NOFILE)) {
|
|
||||||
if (url_fopen(&m->oc->pb, filename, URL_WRONLY) < 0) {
|
|
||||||
fprintf(stderr, "Could not open '%s'\n", filename.data());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write the stream header, if any */
|
|
||||||
av_write_header(m->oc);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoEncoder::Frame(const unsigned char* buffer)
|
|
||||||
{
|
|
||||||
double video_pts = (double)m->video_st->pts.val * m->video_st->time_base.num / m->video_st->time_base.den;
|
|
||||||
if (video_pts >= m->duration)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m->write_video_frame(m->oc, m->video_st, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoEncoder::~VideoEncoder()
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
double video_pts = (double)m->video_st->pts.val * m->video_st->time_base.num / m->video_st->time_base.den;
|
|
||||||
if (video_pts >= m->duration)
|
|
||||||
break;
|
|
||||||
|
|
||||||
m->write_video_frame(m->oc, m->video_st, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* close each codec */
|
|
||||||
if (m->video_st)
|
|
||||||
m->close_video(m->oc, m->video_st);
|
|
||||||
|
|
||||||
/* write the trailer, if any */
|
|
||||||
av_write_trailer(m->oc);
|
|
||||||
|
|
||||||
/* free the streams */
|
|
||||||
for(unsigned int i = 0; i < m->oc->nb_streams; i++) {
|
|
||||||
av_freep(&m->oc->streams[i]->codec);
|
|
||||||
av_freep(&m->oc->streams[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(m->fmt->flags & AVFMT_NOFILE)) {
|
|
||||||
/* close the output file */
|
|
||||||
url_fclose(&m->oc->pb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* free the stream */
|
|
||||||
av_free(m->oc);
|
|
||||||
|
|
||||||
|
|
||||||
delete m;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // !USE_FFMPEG:
|
|
||||||
|
|
||||||
VideoEncoder::VideoEncoder(const wxString& WXUNUSED(filenameStr), int WXUNUSED(framerate), int WXUNUSED(bitrate), float WXUNUSED(duration), int WXUNUSED(width), int WXUNUSED(height))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoEncoder::Frame(const unsigned char* WXUNUSED(buffer))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoEncoder::~VideoEncoder()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !USE_FFMPEG
|
|
@ -1,34 +0,0 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
|
||||||
* This file is part of 0 A.D.
|
|
||||||
*
|
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* 0 A.D. is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDED_FFMPEG
|
|
||||||
#define INCLUDED_FFMPEG
|
|
||||||
|
|
||||||
struct VideoEncoderImpl;
|
|
||||||
|
|
||||||
class VideoEncoder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VideoEncoder(const wxString& filename, int framerate, int bitrate, float duration, int width, int height);
|
|
||||||
void Frame(const unsigned char* buffer);
|
|
||||||
~VideoEncoder();
|
|
||||||
|
|
||||||
private:
|
|
||||||
VideoEncoderImpl* m;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // INCLUDED_FFMPEG
|
|
@ -1,207 +0,0 @@
|
|||||||
/* Copyright (C) 2011 Wildfire Games.
|
|
||||||
* This file is part of 0 A.D.
|
|
||||||
*
|
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* 0 A.D. is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "precompiled.h"
|
|
||||||
|
|
||||||
#include "VideoRecorder.h"
|
|
||||||
|
|
||||||
#include "FFmpeg.h"
|
|
||||||
|
|
||||||
#include "GameInterface/Messages.h"
|
|
||||||
|
|
||||||
using namespace AtlasMessage;
|
|
||||||
|
|
||||||
class RecorderDialog : public wxDialog
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ID_FILENAME,
|
|
||||||
ID_FILECHOOSE,
|
|
||||||
ID_FRAMERATE,
|
|
||||||
ID_BITRATE,
|
|
||||||
ID_DURATION,
|
|
||||||
ID_FILESIZE
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
RecorderDialog(wxWindow* parent, float duration)
|
|
||||||
: wxDialog(parent, wxID_ANY, (wxString)_("Video recording options")),
|
|
||||||
m_Duration(duration)
|
|
||||||
{
|
|
||||||
wxArrayString framerates;
|
|
||||||
framerates.Add(_T("10"));
|
|
||||||
framerates.Add(_T("15"));
|
|
||||||
framerates.Add(_T("25"));
|
|
||||||
framerates.Add(_T("30"));
|
|
||||||
framerates.Add(_T("60"));
|
|
||||||
wxString framerateDefault = _T("25");
|
|
||||||
|
|
||||||
wxArrayString bitrates;
|
|
||||||
bitrates.Add(_T("500"));
|
|
||||||
bitrates.Add(_T("800"));
|
|
||||||
bitrates.Add(_T("1200"));
|
|
||||||
bitrates.Add(_T("1600"));
|
|
||||||
bitrates.Add(_T("3200"));
|
|
||||||
wxString bitrateDefault = _T("1200");
|
|
||||||
|
|
||||||
|
|
||||||
wxSizer* filenameSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
filenameSizer->Add(new wxTextCtrl(this, ID_FILENAME, _T("")), wxSizerFlags().Proportion(1));
|
|
||||||
filenameSizer->Add(new wxButton(this, ID_FILECHOOSE, _("Browse...")));
|
|
||||||
|
|
||||||
wxGridSizer* gridSizer = new wxGridSizer(4);
|
|
||||||
|
|
||||||
gridSizer->Add(new wxStaticText(this, -1, _("Framerate (fps)")), wxSizerFlags().Right().Border(wxRIGHT, 4));
|
|
||||||
gridSizer->Add(new wxComboBox(this, ID_FRAMERATE, framerateDefault, wxDefaultPosition, wxDefaultSize, framerates), wxSizerFlags().Proportion(1).Expand());
|
|
||||||
// TODO: use a wxValidator to only allow digits
|
|
||||||
|
|
||||||
gridSizer->Add(new wxStaticText(this, -1, _("Duration (seconds):")), wxSizerFlags().Right().Border(wxLEFT, 4));
|
|
||||||
gridSizer->Add(new wxStaticText(this, ID_DURATION, wxString::Format(_T("%.1f"), m_Duration)), wxSizerFlags().Expand().Border(wxLEFT, 4));
|
|
||||||
|
|
||||||
gridSizer->Add(new wxStaticText(this, -1, _("Bitrate (Kbit/s)")), wxSizerFlags().Right().Border(wxRIGHT, 4));
|
|
||||||
gridSizer->Add(new wxComboBox(this, ID_BITRATE, bitrateDefault, wxDefaultPosition, wxDefaultSize, bitrates), wxSizerFlags().Proportion(1).Expand());
|
|
||||||
|
|
||||||
gridSizer->Add(new wxStaticText(this, -1, _("Estimated file size:")), wxSizerFlags().Right().Border(wxRIGHT, 4));
|
|
||||||
gridSizer->Add(new wxStaticText(this, ID_FILESIZE, L"???"), wxSizerFlags().Expand().Border(wxLEFT, 4));
|
|
||||||
|
|
||||||
RecalculateSizes_();
|
|
||||||
|
|
||||||
wxSizer* gridSizerBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Compression options"));
|
|
||||||
gridSizerBox->Add(gridSizer, wxSizerFlags().Border(wxALL, 10));
|
|
||||||
|
|
||||||
wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
|
|
||||||
wxButton* okButton = new wxButton(this, wxID_OK, _("Save"));
|
|
||||||
okButton->SetDefault();
|
|
||||||
buttonSizer->AddButton(okButton);
|
|
||||||
buttonSizer->AddButton(new wxButton(this, wxID_CANCEL, _("Cancel")));
|
|
||||||
buttonSizer->Realize();
|
|
||||||
|
|
||||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
sizer->Add(filenameSizer, wxSizerFlags().Border(wxALL, 10).Expand());
|
|
||||||
sizer->Add(gridSizerBox, wxSizerFlags().Border(wxALL, 10));
|
|
||||||
sizer->Add(buttonSizer, wxSizerFlags().Border(wxALL, 10).Centre());
|
|
||||||
|
|
||||||
SetSizer(sizer);
|
|
||||||
sizer->SetSizeHints(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Outputs:
|
|
||||||
wxString m_Filename;
|
|
||||||
unsigned long m_Framerate;
|
|
||||||
unsigned long m_Bitrate;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void OnButtonOK(wxCommandEvent& event)
|
|
||||||
{
|
|
||||||
wxTextCtrl* filenameWin = wxDynamicCast(FindWindow(ID_FILENAME), wxTextCtrl);
|
|
||||||
wxComboBox* framerateWin = wxDynamicCast(FindWindow(ID_FRAMERATE), wxComboBox);
|
|
||||||
wxComboBox* bitrateWin = wxDynamicCast(FindWindow(ID_BITRATE), wxComboBox);
|
|
||||||
|
|
||||||
wxCHECK(filenameWin && framerateWin && bitrateWin, );
|
|
||||||
|
|
||||||
m_Filename = filenameWin->GetValue();
|
|
||||||
if (m_Filename.IsEmpty())
|
|
||||||
{
|
|
||||||
wxLogError(_("No filename specified."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!framerateWin->GetValue().ToULong(&m_Framerate) ||
|
|
||||||
!bitrateWin->GetValue().ToULong(&m_Bitrate))
|
|
||||||
{
|
|
||||||
wxLogError(_("Invalid framerate/bitrate."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.Skip(); // janwas: wxDialog::OnOK has been removed in 2.8 wxw; see http://wxforum.shadonet.com/viewtopic.php?t=11103
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void RecalculateSizes(wxCommandEvent& WXUNUSED(event)) { RecalculateSizes_(); }
|
|
||||||
void RecalculateSizes_()
|
|
||||||
{
|
|
||||||
wxComboBox* framerateWin = wxDynamicCast(FindWindow(ID_FRAMERATE), wxComboBox);
|
|
||||||
wxComboBox* bitrateWin = wxDynamicCast(FindWindow(ID_BITRATE), wxComboBox);
|
|
||||||
wxStaticText* filesizeWin = wxDynamicCast(FindWindow(ID_FILESIZE), wxStaticText);
|
|
||||||
wxCHECK(framerateWin && bitrateWin && filesizeWin, );
|
|
||||||
unsigned long framerate = 0, bitrate = 0;
|
|
||||||
if (!framerateWin->GetValue().ToULong(&framerate) || !bitrateWin->GetValue().ToULong(&bitrate))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int size = m_Duration * bitrate * 1000/8;
|
|
||||||
wxString sizeStr;
|
|
||||||
if (size < 1024*1024) sizeStr = wxString::Format(_T("~%.0f KiB"), (float)size/1024);
|
|
||||||
else if (size < 1024*1024*100) sizeStr = wxString::Format(_T("~%.1f MiB"), (float)size/(1024*1024));
|
|
||||||
else if (size < 1024*1024*1024) sizeStr = wxString::Format(_T("~%.0f MiB"), (float)size/(1024*1024));
|
|
||||||
else sizeStr = wxString::Format(_T("~%.2f GiB"), (float)size/(1024*1024*1024));
|
|
||||||
filesizeWin->SetLabel(sizeStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileBrowse(wxCommandEvent& WXUNUSED(event))
|
|
||||||
{
|
|
||||||
wxTextCtrl* filenameWin = wxDynamicCast(FindWindow(ID_FILENAME), wxTextCtrl);
|
|
||||||
wxCHECK(filenameWin, );
|
|
||||||
|
|
||||||
wxFileDialog dlg (this, wxFileSelectorPromptStr, filenameWin->GetValue(), filenameWin->GetValue(), _("MP4 files (*.mp4)|*.mp4"), wxFD_SAVE);
|
|
||||||
if (dlg.ShowModal() != wxID_OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
filenameWin->SetValue(dlg.GetPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
float m_Duration;
|
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE();
|
|
||||||
};
|
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(RecorderDialog, wxDialog)
|
|
||||||
EVT_COMBOBOX(ID_FRAMERATE, RecorderDialog::RecalculateSizes)
|
|
||||||
EVT_COMBOBOX(ID_BITRATE, RecorderDialog::RecalculateSizes)
|
|
||||||
EVT_TEXT(ID_FRAMERATE, RecorderDialog::RecalculateSizes)
|
|
||||||
EVT_TEXT(ID_BITRATE, RecorderDialog::RecalculateSizes)
|
|
||||||
EVT_BUTTON(ID_FILECHOOSE, RecorderDialog::FileBrowse)
|
|
||||||
EVT_BUTTON(wxID_OK, RecorderDialog::OnButtonOK)
|
|
||||||
END_EVENT_TABLE()
|
|
||||||
|
|
||||||
|
|
||||||
void callback(const sCinemaRecordCB* data, void* cbdata)
|
|
||||||
{
|
|
||||||
VideoEncoder* enc = (VideoEncoder*)cbdata;
|
|
||||||
enc->Frame(data->buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoRecorder::RecordCinematic(wxWindow* window, const wxString& trackName, float duration)
|
|
||||||
{
|
|
||||||
RecorderDialog dlg(window, duration);
|
|
||||||
if (dlg.ShowModal() != wxID_OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
wxStopWatch sw;
|
|
||||||
|
|
||||||
// int w = 320, h = 240;
|
|
||||||
int w = 640, h = 480;
|
|
||||||
|
|
||||||
VideoEncoder venc (dlg.m_Filename, dlg.m_Framerate, dlg.m_Bitrate, duration, w, h);
|
|
||||||
|
|
||||||
qCinemaRecord qry((std::wstring)trackName.wc_str(), dlg.m_Framerate, duration, w, h, Callback<sCinemaRecordCB>(&callback, (void*)&venc));
|
|
||||||
qry.Post();
|
|
||||||
|
|
||||||
wxLogMessage(_("Finished recording (took %.1f seconds)\n"), sw.Time()/1000.f);
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
|
||||||
* This file is part of 0 A.D.
|
|
||||||
*
|
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* 0 A.D. is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDED_VIDEORECORDER
|
|
||||||
#define INCLUDED_VIDEORECORDER
|
|
||||||
|
|
||||||
class VideoRecorder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void RecordCinematic(wxWindow* window, const wxString& trackName, float duration);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // INCLUDED_VIDEORECORDER
|
|
Loading…
Reference in New Issue
Block a user