Initial add of avi recording code for Qt GUI.
This commit is contained in:
parent
69ed92eada
commit
b78003dc00
|
@ -436,8 +436,7 @@ set(SRC_DRIVERS_COMMON
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/vidblit.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/os_utils.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/nes_ntsc.c
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/drivers/videolog/nesvideos-piece.cpp
|
||||
#${CMAKE_CURRENT_SOURCE_DIR}/drivers/videolog/rgbtorgb.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/videolog/rgbtorgb.cpp
|
||||
)
|
||||
|
||||
set(SRC_DRIVERS_SDL
|
||||
|
@ -483,6 +482,10 @@ set(SRC_DRIVERS_SDL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-joystick.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/sdl-throttle.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/unix-netplay.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AviRecord.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/avi-utils.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/fileio.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/avi/gwavi.cpp
|
||||
)
|
||||
|
||||
set(SOURCES ${SRC_CORE} ${SRC_DRIVERS_COMMON} ${SRC_DRIVERS_SDL})
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Qt/AviRecord.h"
|
||||
#include "Qt/avi/gwavi.h"
|
||||
#include "Qt/nes_shm.h"
|
||||
|
||||
static gwavi_t *gwavi = NULL;
|
||||
static bool recordEnable = false;
|
||||
//**************************************************************************************
|
||||
int aviRecordOpenFile( const char *filepath, int format, int width, int height )
|
||||
{
|
||||
if ( gwavi != NULL )
|
||||
{
|
||||
delete gwavi; gwavi = NULL;
|
||||
}
|
||||
|
||||
gwavi = new gwavi_t();
|
||||
|
||||
recordEnable = true;
|
||||
return 0;
|
||||
}
|
||||
//**************************************************************************************
|
||||
int aviRecordAddFrame( void )
|
||||
{
|
||||
if ( !recordEnable )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( gwavi == NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int numPixels, bufferSize;
|
||||
|
||||
numPixels = nes_shm->video.ncol * nes_shm->video.nrow;
|
||||
bufferSize = numPixels * sizeof(uint32_t);
|
||||
|
||||
//gwavi->
|
||||
|
||||
return 0;
|
||||
}
|
||||
//**************************************************************************************
|
||||
int aviRecordClose(void)
|
||||
{
|
||||
recordEnable = false;
|
||||
|
||||
if ( gwavi != NULL )
|
||||
{
|
||||
delete gwavi; gwavi = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//**************************************************************************************
|
|
@ -0,0 +1,9 @@
|
|||
// AviRecord.h
|
||||
//
|
||||
|
||||
int aviRecordOpenFile( const char *filepath, int format, int width, int height );
|
||||
|
||||
int aviRecordAddFrame( void );
|
||||
|
||||
int aviRecordClose(void);
|
||||
|
|
@ -63,6 +63,7 @@
|
|||
#include "Qt/PaletteConf.h"
|
||||
#include "Qt/PaletteEditor.h"
|
||||
#include "Qt/GuiConf.h"
|
||||
#include "Qt/AviRecord.h"
|
||||
#include "Qt/MoviePlay.h"
|
||||
#include "Qt/MovieOptions.h"
|
||||
#include "Qt/TimingConf.h"
|
||||
|
@ -1446,6 +1447,15 @@ void consoleWin_t::createMainMenu(void)
|
|||
|
||||
movieMenu->addAction(recAsMovAct);
|
||||
|
||||
// Movie -> Avi Record
|
||||
act = new QAction(tr("A&VI Record"), this);
|
||||
//act->setShortcut( QKeySequence(tr("Shift+F5")));
|
||||
act->setCheckable(true);
|
||||
act->setStatusTip(tr("AVI Record"));
|
||||
connect(act, SIGNAL(triggered()), this, SLOT(aviOpen(void)) );
|
||||
|
||||
movieMenu->addAction(act);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Help
|
||||
helpMenu = menubar->addMenu(tr("&Help"));
|
||||
|
@ -3084,6 +3094,11 @@ void consoleWin_t::recordMovieAs(void)
|
|||
return;
|
||||
}
|
||||
|
||||
void consoleWin_t::aviOpen(void)
|
||||
{
|
||||
aviRecordOpenFile( NULL, 0, 256, 240 );
|
||||
}
|
||||
|
||||
void consoleWin_t::aboutFCEUX(void)
|
||||
{
|
||||
AboutWindow *aboutWin;
|
||||
|
|
|
@ -357,6 +357,7 @@ class consoleWin_t : public QMainWindow
|
|||
void mainMenuOpen(void);
|
||||
void mainMenuClose(void);
|
||||
void warnAmbiguousShortcut( QShortcut*);
|
||||
void aviOpen(void);
|
||||
|
||||
};
|
||||
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,560 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2011, Michael Kohn
|
||||
* Copyright (c) 2013, Robin Hahling
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set of functions useful to create an AVI file. It is used to write things
|
||||
* such as AVI header and so on.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Qt/avi/gwavi.h"
|
||||
|
||||
int
|
||||
gwavi_t::write_avi_header(FILE *out, struct gwavi_header_t *avi_header)
|
||||
{
|
||||
long marker, t;
|
||||
|
||||
if (write_chars_bin(out, "avih", 4) == -1) {
|
||||
(void)fprintf(stderr, "write_avi_header: write_chars_bin() "
|
||||
"failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ((marker = ftell(out)) == -1) {
|
||||
perror("write_avi_header (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (write_int(out, avi_header->time_delay) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->data_rate) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->reserved) == -1)
|
||||
goto write_int_failed;
|
||||
/* dwFlags */
|
||||
if (write_int(out, avi_header->flags) == -1)
|
||||
goto write_int_failed;
|
||||
/* dwTotalFrames */
|
||||
if (write_int(out, avi_header->number_of_frames) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->initial_frames) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->data_streams) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->buffer_size) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->width) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->height) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->time_scale) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->playback_data_rate) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->starting_time) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, avi_header->data_length) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if ((t = ftell(out)) == -1) {
|
||||
perror("write_avi_header (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out, marker, SEEK_SET) == -1) {
|
||||
perror("write_avi_header (fseek)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, (unsigned int)(t - marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
if (fseek(out, t, SEEK_SET) == -1) {
|
||||
perror("write_avi_header (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
write_int_failed:
|
||||
(void)fprintf(stderr, "write_avi_header: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_stream_header(FILE *out, struct gwavi_stream_header_t *stream_header)
|
||||
{
|
||||
long marker, t;
|
||||
|
||||
if (write_chars_bin(out, "strh", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if ((marker = ftell(out)) == -1) {
|
||||
perror("write_stream_header (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (write_chars_bin(out, stream_header->data_type, 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_chars_bin(out, stream_header->codec, 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_int(out, stream_header->flags) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->priority) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->initial_frames) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->time_scale) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->data_rate) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->start_time) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->data_length) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->buffer_size) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->video_quality) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_header->sample_size) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if ((t = ftell(out)) == -1) {
|
||||
perror("write_stream_header (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out, marker, SEEK_SET) == -1) {
|
||||
perror("write_stream_header (fseek)");
|
||||
return -1;
|
||||
}
|
||||
write_int(out, (unsigned int)(t - marker - 4));
|
||||
if (fseek(out, t, SEEK_SET) == -1){
|
||||
perror("write_stream_header (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
write_int_failed:
|
||||
(void)fprintf(stderr, "write_stream_header: write_int() failed\n");
|
||||
return -1;
|
||||
|
||||
write_chars_bin_failed:
|
||||
(void)fprintf(stderr, "write_stream_header: write_chars_bin() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_stream_format_v(FILE *out, struct gwavi_stream_format_v_t *stream_format_v)
|
||||
{
|
||||
long marker,t;
|
||||
unsigned int i;
|
||||
|
||||
if (write_chars_bin(out, "strf", 4) == -1) {
|
||||
(void)fprintf(stderr, "write_stream_format_v: write_chars_bin()"
|
||||
" failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ((marker = ftell(out)) == -1) {
|
||||
perror("write_stream_format_v (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (write_int(out, stream_format_v->header_size) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_v->width) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_v->height) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_short(out, stream_format_v->num_planes) == -1) {
|
||||
(void)fprintf(stderr, "write_stream_format_v: write_short() "
|
||||
"failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_short(out, stream_format_v->bits_per_pixel) == -1) {
|
||||
(void)fprintf(stderr, "write_stream_format_v: write_short() "
|
||||
"failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, stream_format_v->compression_type) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_v->image_size) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_v->x_pels_per_meter) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_v->y_pels_per_meter) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_v->colors_used) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_v->colors_important) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (stream_format_v->colors_used != 0)
|
||||
for (i = 0; i < stream_format_v->colors_used; i++) {
|
||||
if (fputc(stream_format_v->palette[i] & 255, out)
|
||||
== EOF)
|
||||
goto fputc_failed;
|
||||
if (fputc((stream_format_v->palette[i] >> 8) & 255, out)
|
||||
== EOF)
|
||||
goto fputc_failed;
|
||||
if (fputc((stream_format_v->palette[i] >> 16) & 255, out)
|
||||
== EOF)
|
||||
goto fputc_failed;
|
||||
if (fputc(0, out) == EOF)
|
||||
goto fputc_failed;
|
||||
}
|
||||
|
||||
if ((t = ftell(out)) == -1) {
|
||||
perror("write_stream_format_v (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out,marker,SEEK_SET) == -1) {
|
||||
perror("write_stream_format_v (fseek)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, (unsigned int)(t - marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
if (fseek(out, t, SEEK_SET) == -1) {
|
||||
perror("write_stream_format_v (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
write_int_failed:
|
||||
(void)fprintf(stderr, "write_stream_format_v: write_int() failed\n");
|
||||
return -1;
|
||||
|
||||
fputc_failed:
|
||||
(void)fprintf(stderr, "write_stream_format_v: fputc() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_stream_format_a(FILE *out, struct gwavi_stream_format_a_t *stream_format_a)
|
||||
{
|
||||
long marker, t;
|
||||
|
||||
if (write_chars_bin(out, "strf", 4) == -1) {
|
||||
(void)fprintf(stderr, "write_stream_format_a: write_chars_bin()"
|
||||
" failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ((marker = ftell(out)) == -1) {
|
||||
perror("write_stream_format_a (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
if (write_short(out, stream_format_a->format_type) == -1)
|
||||
goto write_short_failed;
|
||||
if (write_short(out, stream_format_a->channels) == -1)
|
||||
goto write_short_failed;
|
||||
if (write_int(out, stream_format_a->sample_rate) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, stream_format_a->bytes_per_second) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_short(out, stream_format_a->block_align) == -1)
|
||||
goto write_short_failed;
|
||||
if (write_short(out, stream_format_a->bits_per_sample) == -1)
|
||||
goto write_short_failed;
|
||||
if (write_short(out, stream_format_a->size) == -1)
|
||||
goto write_short_failed;
|
||||
|
||||
if ((t = ftell(out)) == -1) {
|
||||
perror("write_stream_format_a (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out, marker, SEEK_SET) == -1) {
|
||||
perror("write_stream_format_a (fseek)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, (unsigned int)(t - marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
if (fseek(out, t, SEEK_SET) == -1) {
|
||||
perror("write_stream_format_a (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
write_int_failed:
|
||||
(void)fprintf(stderr, "write_stream_format_a: write_int() failed\n");
|
||||
return -1;
|
||||
|
||||
write_short_failed:
|
||||
(void)fprintf(stderr, "write_stream_format_a: write_short() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_avi_header_chunk(void)
|
||||
{
|
||||
long marker, t;
|
||||
long sub_marker;
|
||||
|
||||
if (write_chars_bin(out, "LIST", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if ((marker = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_chars_bin(out, "hdrl", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_avi_header(out, &avi_header) == -1) {
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_avi_header() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write_chars_bin(out, "LIST", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if ((sub_marker = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_chars_bin(out, "strl", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_stream_header(out, &stream_header_v) == -1) {
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_header failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_stream_format_v(out, &stream_format_v) == -1) {
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_format_v failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((t = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
|
||||
if (fseek(out, sub_marker, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
if (write_int(out, (unsigned int)(t - sub_marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
if (fseek(out, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (avi_header.data_streams == 2) {
|
||||
if (write_chars_bin(out, "LIST", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if ((sub_marker = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_chars_bin(out, "strl", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_stream_header(out, &stream_header_a) == -1) {
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_header failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_stream_format_a(out, &stream_format_a) == -1) {
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: "
|
||||
"write_stream_format_a failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((t = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (fseek(out, sub_marker, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
if (write_int(out, (unsigned int)(t - sub_marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
if (fseek(out, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
}
|
||||
|
||||
if ((t = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (fseek(out, marker, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
if (write_int(out, (unsigned int)(t - marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
if (fseek(out, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
return 0;
|
||||
|
||||
ftell_failed:
|
||||
perror("write_avi_header_chunk (ftell)");
|
||||
return -1;
|
||||
|
||||
fseek_failed:
|
||||
perror("write_avi_header_chunk (fseek)");
|
||||
return -1;
|
||||
|
||||
write_int_failed:
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: write_int() failed\n");
|
||||
return -1;
|
||||
|
||||
write_chars_bin_failed:
|
||||
(void)fprintf(stderr, "write_avi_header_chunk: write_chars_bin() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_index(FILE *out, int count, unsigned int *offsets)
|
||||
{
|
||||
long marker, t;
|
||||
unsigned int offset = 4;
|
||||
|
||||
if (offsets == 0)
|
||||
return -1;
|
||||
|
||||
if (write_chars_bin(out, "idx1", 4) == -1) {
|
||||
(void)fprintf(stderr, "write_index: write_chars_bin) failed\n");
|
||||
return -1;
|
||||
}
|
||||
if ((marker = ftell(out)) == -1) {
|
||||
perror("write_index (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, 0) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
for (t = 0; t < count; t++) {
|
||||
if ((offsets[t] & 0x80000000) == 0)
|
||||
write_chars(out, "00dc");
|
||||
else {
|
||||
write_chars(out, "01wb");
|
||||
offsets[t] &= 0x7fffffff;
|
||||
}
|
||||
if (write_int(out, 0x10) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, offset) == -1)
|
||||
goto write_int_failed;
|
||||
if (write_int(out, offsets[t]) == -1)
|
||||
goto write_int_failed;
|
||||
|
||||
offset = offset + offsets[t] + 8;
|
||||
}
|
||||
|
||||
if ((t = ftell(out)) == -1) {
|
||||
perror("write_index (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out, marker, SEEK_SET) == -1) {
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, (unsigned int)(t - marker - 4)) == -1)
|
||||
goto write_int_failed;
|
||||
if (fseek(out, t, SEEK_SET) == -1) {
|
||||
perror("write_index (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
write_int_failed:
|
||||
(void)fprintf(stderr, "write_index: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 0 if fourcc is valid, 1 non-valid or -1 in case of errors.
|
||||
*/
|
||||
int
|
||||
gwavi_t::check_fourcc(const char *fourcc)
|
||||
{
|
||||
int ret = 0;
|
||||
/* list of fourccs from http://fourcc.org/codecs.php */
|
||||
const char valid_fourcc[] =
|
||||
"3IV1 3IV2 8BPS"
|
||||
"AASC ABYR ADV1 ADVJ AEMI AFLC AFLI AJPG AMPG ANIM AP41 ASLC"
|
||||
"ASV1 ASV2 ASVX AUR2 AURA AVC1 AVRN"
|
||||
"BA81 BINK BLZ0 BT20 BTCV BW10 BYR1 BYR2"
|
||||
"CC12 CDVC CFCC CGDI CHAM CJPG CMYK CPLA CRAM CSCD CTRX CVID"
|
||||
"CWLT CXY1 CXY2 CYUV CYUY"
|
||||
"D261 D263 DAVC DCL1 DCL2 DCL3 DCL4 DCL5 DIV3 DIV4 DIV5 DIVX"
|
||||
"DM4V DMB1 DMB2 DMK2 DSVD DUCK DV25 DV50 DVAN DVCS DVE2 DVH1"
|
||||
"DVHD DVSD DVSL DVX1 DVX2 DVX3 DX50 DXGM DXTC DXTN"
|
||||
"EKQ0 ELK0 EM2V ES07 ESCP ETV1 ETV2 ETVC"
|
||||
"FFV1 FLJP FMP4 FMVC FPS1 FRWA FRWD FVF1"
|
||||
"GEOX GJPG GLZW GPEG GWLT"
|
||||
"H260 H261 H262 H263 H264 H265 H266 H267 H268 H269"
|
||||
"HDYC HFYU HMCR HMRR"
|
||||
"I263 ICLB IGOR IJPG ILVC ILVR IPDV IR21 IRAW ISME"
|
||||
"IV30 IV31 IV32 IV33 IV34 IV35 IV36 IV37 IV38 IV39 IV40 IV41"
|
||||
"IV41 IV43 IV44 IV45 IV46 IV47 IV48 IV49 IV50"
|
||||
"JBYR JPEG JPGL"
|
||||
"KMVC"
|
||||
"L261 L263 LBYR LCMW LCW2 LEAD LGRY LJ11 LJ22 LJ2K LJ44 LJPG"
|
||||
"LMP2 LMP4 LSVC LSVM LSVX LZO1"
|
||||
"M261 M263 M4CC M4S2 MC12 MCAM MJ2C MJPG MMES MP2A MP2T MP2V"
|
||||
"MP42 MP43 MP4A MP4S MP4T MP4V MPEG MPG4 MPGI MR16 MRCA MRLE"
|
||||
"MSVC MSZH"
|
||||
"MTX1 MTX2 MTX3 MTX4 MTX5 MTX6 MTX7 MTX8 MTX9"
|
||||
"MVI1 MVI2 MWV1"
|
||||
"NAVI NDSC NDSM NDSP NDSS NDXC NDXH NDXP NDXS NHVU NTN1 NTN2"
|
||||
"NVDS NVHS"
|
||||
"NVS0 NVS1 NVS2 NVS3 NVS4 NVS5"
|
||||
"NVT0 NVT1 NVT2 NVT3 NVT4 NVT5"
|
||||
"PDVC PGVV PHMO PIM1 PIM2 PIMJ PIXL PJPG PVEZ PVMM PVW2"
|
||||
"QPEG QPEQ"
|
||||
"RGBT RLE RLE4 RLE8 RMP4 RPZA RT21 RV20 RV30 RV40 S422 SAN3"
|
||||
"SDCC SEDG SFMC SMP4 SMSC SMSD SMSV SP40 SP44 SP54 SPIG SQZ2"
|
||||
"STVA STVB STVC STVX STVY SV10 SVQ1 SVQ3"
|
||||
"TLMS TLST TM20 TM2X TMIC TMOT TR20 TSCC TV10 TVJP TVMJ TY0N"
|
||||
"TY2C TY2N"
|
||||
"UCOD ULTI"
|
||||
"V210 V261 V655 VCR1 VCR2 VCR3 VCR4 VCR5 VCR6 VCR7 VCR8 VCR9"
|
||||
"VDCT VDOM VDTZ VGPX VIDS VIFP VIVO VIXL VLV1 VP30 VP31 VP40"
|
||||
"VP50 VP60 VP61 VP62 VP70 VP80 VQC1 VQC2 VQJC VSSV VUUU VX1K"
|
||||
"VX2K VXSP VYU9 VYUY"
|
||||
"WBVC WHAM WINX WJPG WMV1 WMV2 WMV3 WMVA WNV1 WVC1"
|
||||
"X263 X264 XLV0 XMPG XVID"
|
||||
"XWV0 XWV1 XWV2 XWV3 XWV4 XWV5 XWV6 XWV7 XWV8 XWV9"
|
||||
"XXAN"
|
||||
"Y16 Y411 Y41P Y444 Y8 YC12 YUV8 YUV9 YUVP YUY2 YUYV YV12 YV16"
|
||||
"YV92"
|
||||
"ZLIB ZMBV ZPEG ZYGO ZYYY";
|
||||
|
||||
if (!fourcc) {
|
||||
(void)fputs("fourcc cannot be NULL", stderr);
|
||||
return -1;
|
||||
}
|
||||
if (strchr(fourcc, ' ') || !strstr(valid_fourcc, fourcc))
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2011, Michael Kohn
|
||||
* Copyright (c) 2013, Robin Hahling
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Usefull IO functions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gwavi.h"
|
||||
|
||||
int
|
||||
gwavi_t::write_int(FILE *out, unsigned int n)
|
||||
{
|
||||
unsigned char buffer[4];
|
||||
|
||||
buffer[0] = n;
|
||||
buffer[1] = n >> 8;
|
||||
buffer[2] = n >> 16;
|
||||
buffer[3] = n >> 24;
|
||||
|
||||
if (fwrite(buffer, 1, 4, out) != 4)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_short(FILE *out, unsigned int n)
|
||||
{
|
||||
unsigned char buffer[2];
|
||||
|
||||
buffer[0] = n;
|
||||
buffer[1] = n >> 8;
|
||||
|
||||
if (fwrite(buffer, 1, 2, out) != 2)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_chars(FILE *out, const char *s)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
while(s[t] != 0 && t < 255)
|
||||
if (fputc(s[t++], out) == EOF)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gwavi_t::write_chars_bin(FILE *out, const char *s, int count)
|
||||
{
|
||||
if (fwrite(s, 1, count, out) != count)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2011, Michael Kohn
|
||||
* Copyright (c) 2013, Robin Hahling
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the file containing gwavi library functions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gwavi.h"
|
||||
|
||||
/**
|
||||
* This is the first function you should call when using gwavi library.
|
||||
* It allocates memory for a gwavi_t structure and returns it and takes care of
|
||||
* initializing the AVI header with the provided information.
|
||||
*
|
||||
* When you're done creating your AVI file, you should call gwavi_close()
|
||||
* function to free memory allocated for the gwavi_t structure and properly
|
||||
* close the output file.
|
||||
*
|
||||
* @param filename This is the name of the AVI file which will be generated by
|
||||
* this library.
|
||||
* @param width Width of a frame.
|
||||
* @param height Height of a frame.
|
||||
* @param fourcc FourCC representing the codec of the video encoded stream. a
|
||||
* FourCC is a sequence of four chars used to uniquely identify data formats.
|
||||
* For more information, you can visit www.fourcc.org.
|
||||
* @param fps Number of frames per second of your video. It needs to be > 0.
|
||||
* @param audio This parameter is optionnal. It is used for the audio track. If
|
||||
* you do not want to add an audio track to your AVI file, simply pass NULL for
|
||||
* this argument.
|
||||
*
|
||||
* @return Structure containing required information in order to create the AVI
|
||||
* file. If an error occured, NULL is returned.
|
||||
*/
|
||||
|
||||
gwavi_t::gwavi_t(void)
|
||||
{
|
||||
out = NULL;
|
||||
memset( &avi_header , 0, sizeof(struct gwavi_header_t) );
|
||||
memset( &stream_header_v, 0, sizeof(struct gwavi_stream_header_t) );
|
||||
memset( &stream_format_v, 0, sizeof(struct gwavi_stream_format_v_t) );
|
||||
memset( &stream_header_a, 0, sizeof(struct gwavi_stream_header_t) );
|
||||
memset( &stream_format_a, 0, sizeof(struct gwavi_stream_format_a_t) );
|
||||
marker = 0;
|
||||
offsets_ptr = 0;
|
||||
offsets_len = 0;
|
||||
offsets_start = 0;
|
||||
offsets = 0;
|
||||
offset_count = 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gwavi_t::open(const char *filename, unsigned int width, unsigned int height,
|
||||
const char *fourcc, unsigned int fps, struct gwavi_audio_t *audio)
|
||||
{
|
||||
if (check_fourcc(fourcc) != 0)
|
||||
(void)fprintf(stderr, "WARNING: given fourcc does not seem to "
|
||||
"be valid: %s\n", fourcc);
|
||||
if (fps < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if ((out = fopen(filename, "wb+")) == NULL)
|
||||
{
|
||||
perror("gwavi_open: failed to open file for writing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set avi header */
|
||||
avi_header.time_delay= 1000000 / fps;
|
||||
avi_header.data_rate = width * height * 3;
|
||||
avi_header.flags = 0x10;
|
||||
|
||||
if (audio)
|
||||
avi_header.data_streams = 2;
|
||||
else
|
||||
avi_header.data_streams = 1;
|
||||
|
||||
/* this field gets updated when calling gwavi_close() */
|
||||
avi_header.number_of_frames = 0;
|
||||
avi_header.width = width;
|
||||
avi_header.height = height;
|
||||
avi_header.buffer_size = (width * height * 3);
|
||||
|
||||
/* set stream header */
|
||||
(void)strcpy(stream_header_v.data_type, "vids");
|
||||
(void)memcpy(stream_header_v.codec, fourcc, 4);
|
||||
stream_header_v.time_scale = 1;
|
||||
stream_header_v.data_rate = fps;
|
||||
stream_header_v.buffer_size = (width * height * 3);
|
||||
stream_header_v.data_length = 0;
|
||||
|
||||
/* set stream format */
|
||||
stream_format_v.header_size = 40;
|
||||
stream_format_v.width = width;
|
||||
stream_format_v.height = height;
|
||||
stream_format_v.num_planes = 1;
|
||||
stream_format_v.bits_per_pixel = 24;
|
||||
stream_format_v.compression_type =
|
||||
((unsigned int)fourcc[3] << 24) +
|
||||
((unsigned int)fourcc[2] << 16) +
|
||||
((unsigned int)fourcc[1] << 8) +
|
||||
((unsigned int)fourcc[0]);
|
||||
stream_format_v.image_size = width * height * 3;
|
||||
stream_format_v.colors_used = 0;
|
||||
stream_format_v.colors_important = 0;
|
||||
|
||||
stream_format_v.palette = 0;
|
||||
stream_format_v.palette_count = 0;
|
||||
|
||||
if (audio)
|
||||
{
|
||||
/* set stream header */
|
||||
memcpy(stream_header_a.data_type, "auds", 4);
|
||||
stream_header_a.codec[0] = 1;
|
||||
stream_header_a.codec[1] = 0;
|
||||
stream_header_a.codec[2] = 0;
|
||||
stream_header_a.codec[3] = 0;
|
||||
stream_header_a.time_scale = 1;
|
||||
stream_header_a.data_rate = audio->samples_per_second;
|
||||
stream_header_a.buffer_size =
|
||||
audio->channels * (audio->bits / 8) * audio->samples_per_second;
|
||||
/* when set to -1, drivers use default quality value */
|
||||
stream_header_a.audio_quality = -1;
|
||||
stream_header_a.sample_size =
|
||||
(audio->bits / 8) * audio->channels;
|
||||
|
||||
/* set stream format */
|
||||
stream_format_a.format_type = 1;
|
||||
stream_format_a.channels = audio->channels;
|
||||
stream_format_a.sample_rate = audio->samples_per_second;
|
||||
stream_format_a.bytes_per_second =
|
||||
audio->channels * (audio->bits / 8) * audio->samples_per_second;
|
||||
stream_format_a.block_align =
|
||||
audio->channels * (audio->bits / 8);
|
||||
stream_format_a.bits_per_sample = audio->bits;
|
||||
stream_format_a.size = 0;
|
||||
}
|
||||
|
||||
if (write_chars_bin(out, "RIFF", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if (write_int(out, 0) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_info: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_chars_bin(out, "AVI ", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
|
||||
if (write_avi_header_chunk() == -1) {
|
||||
(void)fprintf(stderr, "gwavi_info: write_avi_header_chunk "
|
||||
"failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write_chars_bin(out, "LIST", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
if ((marker = ftell(out)) == -1) {
|
||||
perror("gwavi_info (ftell)");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, 0) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_info: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_chars_bin(out, "movi", 4) == -1)
|
||||
goto write_chars_bin_failed;
|
||||
|
||||
offsets_len = 1024;
|
||||
if ((offsets = (unsigned int *)malloc((size_t)offsets_len *
|
||||
sizeof(unsigned int)))
|
||||
== NULL) {
|
||||
(void)fprintf(stderr, "gwavi_info: could not allocate memory "
|
||||
"for gwavi offsets table\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
offsets_ptr = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
write_chars_bin_failed:
|
||||
(void)fprintf(stderr, "gwavi_open: write_chars_bin() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to add an encoded video frame to the AVI file.
|
||||
*
|
||||
* @param gwavi Main gwavi structure initialized with gwavi_open()-
|
||||
* @param buffer Video buffer size.
|
||||
* @param len Video buffer length.
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
gwavi_t::add_frame( unsigned char *buffer, size_t len)
|
||||
{
|
||||
size_t maxi_pad; /* if your frame is raggin, give it some paddin' */
|
||||
size_t t;
|
||||
|
||||
if ( !buffer) {
|
||||
(void)fputs("gwavi and/or buffer argument cannot be NULL",
|
||||
stderr);
|
||||
return -1;
|
||||
}
|
||||
if (len < 256)
|
||||
(void)fprintf(stderr, "WARNING: specified buffer len seems "
|
||||
"rather small: %d. Are you sure about this?\n",
|
||||
(int)len);
|
||||
|
||||
offset_count++;
|
||||
stream_header_v.data_length++;
|
||||
|
||||
maxi_pad = len % 4;
|
||||
if (maxi_pad > 0)
|
||||
maxi_pad = 4 - maxi_pad;
|
||||
|
||||
if (offset_count >= offsets_len) {
|
||||
offsets_len += 1024;
|
||||
offsets = (unsigned int *)realloc(offsets,
|
||||
(size_t)offsets_len *
|
||||
sizeof(unsigned int));
|
||||
}
|
||||
|
||||
offsets[offsets_ptr++] = (unsigned int)(len + maxi_pad);
|
||||
|
||||
if (write_chars_bin(out, "00dc", 4) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_add_frame: write_chars_bin() "
|
||||
"failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out, (unsigned int)(len + maxi_pad)) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_add_frame: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((t = fwrite(buffer, 1, len, out)) != len) {
|
||||
(void)fprintf(stderr, "gwavi_add_frame: fwrite() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (t = 0; t < maxi_pad; t++)
|
||||
{
|
||||
if (fputc(0, out) == EOF) {
|
||||
(void)fprintf(stderr, "gwavi_add_frame: fputc() failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to add the audio track to your AVI file.
|
||||
*
|
||||
* @param gwavi Main gwavi structure initialized with gwavi_open()-
|
||||
* @param buffer Audio buffer size.
|
||||
* @param len Audio buffer length.
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
gwavi_t::add_audio( unsigned char *buffer, size_t len)
|
||||
{
|
||||
size_t maxi_pad; /* in case audio bleeds over the 4 byte boundary */
|
||||
size_t t;
|
||||
|
||||
if ( !buffer) {
|
||||
(void)fputs("gwavi and/or buffer argument cannot be NULL",
|
||||
stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset_count++;
|
||||
|
||||
maxi_pad = len % 4;
|
||||
if (maxi_pad > 0)
|
||||
maxi_pad = 4 - maxi_pad;
|
||||
|
||||
if (offset_count >= offsets_len) {
|
||||
offsets_len += 1024;
|
||||
offsets = (unsigned int *)realloc(offsets,
|
||||
(size_t)offsets_len *
|
||||
sizeof(unsigned int));
|
||||
}
|
||||
|
||||
offsets[offsets_ptr++] =
|
||||
(unsigned int)((len + maxi_pad) | 0x80000000);
|
||||
|
||||
if (write_chars_bin(out,"01wb",4) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_add_audio: write_chars_bin() "
|
||||
"failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (write_int(out,(unsigned int)(len + maxi_pad)) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_add_audio: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((t = fwrite(buffer, 1, len, out)) != len ) {
|
||||
(void)fprintf(stderr, "gwavi_add_audio: fwrite() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (t = 0; t < maxi_pad; t++)
|
||||
if (fputc(0,out) == EOF) {
|
||||
(void)fprintf(stderr, "gwavi_add_audio: fputc() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_header_a.data_length += (unsigned int)(len + maxi_pad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function should be called when the program is done adding video and/or
|
||||
* audio frames to the AVI file. It frees memory allocated for gwavi_open() for
|
||||
* the main gwavi_t structure. It also properly closes the output file.
|
||||
*
|
||||
* @param gwavi Main gwavi structure initialized with gwavi_open()-
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
gwavi_t::close(void)
|
||||
{
|
||||
long t;
|
||||
|
||||
if ((t = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (fseek(out, marker, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
if (write_int(out, (unsigned int)(t - marker - 4)) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_close: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out,t,SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (write_index(out, offset_count, offsets) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_close: write_index() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(offsets);
|
||||
|
||||
/* reset some avi header fields */
|
||||
avi_header.number_of_frames = stream_header_v.data_length;
|
||||
|
||||
if ((t = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (fseek(out, 12, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
if (write_avi_header_chunk() == -1) {
|
||||
(void)fprintf(stderr, "gwavi_close: write_avi_header_chunk() "
|
||||
"failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if ((t = ftell(out)) == -1)
|
||||
goto ftell_failed;
|
||||
if (fseek(out, 4, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
if (write_int(out, (unsigned int)(t - 8)) == -1) {
|
||||
(void)fprintf(stderr, "gwavi_close: write_int() failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (fseek(out, t, SEEK_SET) == -1)
|
||||
goto fseek_failed;
|
||||
|
||||
if (stream_format_v.palette != 0)
|
||||
free(stream_format_v.palette);
|
||||
|
||||
if (fclose(out) == EOF) {
|
||||
perror("gwavi_close (fclose)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
ftell_failed:
|
||||
perror("gwavi_close: (ftell)");
|
||||
return -1;
|
||||
|
||||
fseek_failed:
|
||||
perror("gwavi_close (fseek)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to reset the framerate. In a standard use case, you
|
||||
* should not need to call it. However, if you need to, you can call it to reset
|
||||
* the framerate after you are done adding frames to your AVI file and before
|
||||
* you call gwavi_close().
|
||||
*
|
||||
* @param gwavi Main gwavi structure initialized with gwavi_open()-
|
||||
* @param fps Number of frames per second of your video.
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
gwavi_t::set_framerate(unsigned int fps)
|
||||
{
|
||||
stream_header_v.data_rate = fps;
|
||||
avi_header.time_delay = (10000000 / fps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to reset the video codec. In a standard use case,
|
||||
* you should not need to call it. However, if you need to, you can call it to
|
||||
* reset the video codec after you are done adding frames to your AVI file and
|
||||
* before you call gwavi_close().
|
||||
*
|
||||
* @param gwavi Main gwavi structure initialized with gwavi_open()-
|
||||
* @param fourcc FourCC representing the codec of the video encoded stream. a
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
gwavi_t::set_codec( const char *fourcc)
|
||||
{
|
||||
if (check_fourcc(fourcc) != 0)
|
||||
(void)fprintf(stderr, "WARNING: given fourcc does not seem to "
|
||||
"be valid: %s\n", fourcc);
|
||||
|
||||
memcpy(stream_header_v.codec, fourcc, 4);
|
||||
stream_format_v.compression_type =
|
||||
((unsigned int)fourcc[3] << 24) +
|
||||
((unsigned int)fourcc[2] << 16) +
|
||||
((unsigned int)fourcc[1] << 8) +
|
||||
((unsigned int)fourcc[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function allows you to reset the video size. In a standard use case, you
|
||||
* should not need to call it. However, if you need to, you can call it to reset
|
||||
* the video height and width set in the AVI file after you are done adding
|
||||
* frames to your AVI file and before you call gwavi_close().
|
||||
*
|
||||
* @param gwavi Main gwavi structure initialized with gwavi_open()-
|
||||
* @param width Width of a frame.
|
||||
* @param height Height of a frame.
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
gwavi_t::set_size( unsigned int width, unsigned int height)
|
||||
{
|
||||
unsigned int size = (width * height * 3);
|
||||
|
||||
avi_header.data_rate = size;
|
||||
avi_header.width = width;
|
||||
avi_header.height = height;
|
||||
avi_header.buffer_size = size;
|
||||
stream_header_v.buffer_size = size;
|
||||
stream_format_v.width = width;
|
||||
stream_format_v.height = height;
|
||||
stream_format_v.image_size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2011, Michael Kohn
|
||||
* Copyright (c) 2013, Robin Hahling
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef H_GWAVI
|
||||
#define H_GWAVI
|
||||
|
||||
#include <stdint.h> /* for size_t */
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
/* structures */
|
||||
struct gwavi_header_t
|
||||
{
|
||||
unsigned int time_delay; /* dwMicroSecPerFrame */
|
||||
unsigned int data_rate; /* dwMaxBytesPerSec */
|
||||
unsigned int reserved;
|
||||
unsigned int flags; /* dwFlags */
|
||||
unsigned int number_of_frames; /* dwTotalFrames */
|
||||
unsigned int initial_frames; /* dwInitialFrames */
|
||||
unsigned int data_streams; /* dwStreams */
|
||||
unsigned int buffer_size; /* dwSuggestedBufferSize */
|
||||
unsigned int width; /* dwWidth */
|
||||
unsigned int height; /* dwHeight */
|
||||
unsigned int time_scale;
|
||||
unsigned int playback_data_rate;
|
||||
unsigned int starting_time;
|
||||
unsigned int data_length;
|
||||
};
|
||||
|
||||
struct gwavi_stream_header_t
|
||||
{
|
||||
char data_type[5]; /* fccType */
|
||||
char codec[5]; /* fccHandler */
|
||||
unsigned int flags; /* dwFlags */
|
||||
unsigned int priority;
|
||||
unsigned int initial_frames;/* dwInitialFrames */
|
||||
unsigned int time_scale; /* dwScale */
|
||||
unsigned int data_rate; /* dwRate */
|
||||
unsigned int start_time; /* dwStart */
|
||||
unsigned int data_length; /* dwLength */
|
||||
unsigned int buffer_size; /* dwSuggestedBufferSize */
|
||||
unsigned int video_quality; /* dwQuality */
|
||||
/**
|
||||
* Value between 0-10000. If set to -1, drivers use default quality
|
||||
* value.
|
||||
*/
|
||||
int audio_quality;
|
||||
unsigned int sample_size; /* dwSampleSize */
|
||||
};
|
||||
|
||||
struct gwavi_stream_format_v_t
|
||||
{
|
||||
unsigned int header_size;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned short int num_planes;
|
||||
unsigned short int bits_per_pixel;
|
||||
unsigned int compression_type;
|
||||
unsigned int image_size;
|
||||
unsigned int x_pels_per_meter;
|
||||
unsigned int y_pels_per_meter;
|
||||
unsigned int colors_used;
|
||||
unsigned int colors_important;
|
||||
unsigned int *palette;
|
||||
unsigned int palette_count;
|
||||
};
|
||||
|
||||
struct gwavi_stream_format_a_t
|
||||
{
|
||||
unsigned short format_type;
|
||||
unsigned int channels;
|
||||
unsigned int sample_rate;
|
||||
unsigned int bytes_per_second;
|
||||
unsigned int block_align;
|
||||
unsigned int bits_per_sample;
|
||||
unsigned short size;
|
||||
};
|
||||
|
||||
struct gwavi_audio_t
|
||||
{
|
||||
unsigned int channels;
|
||||
unsigned int bits;
|
||||
unsigned int samples_per_second;
|
||||
};
|
||||
|
||||
class gwavi_t
|
||||
{
|
||||
public:
|
||||
gwavi_t(void);
|
||||
|
||||
int open(const char *filename, unsigned int width,
|
||||
unsigned int height, const char *fourcc, unsigned int fps,
|
||||
struct gwavi_audio_t *audio);
|
||||
|
||||
int close(void);
|
||||
|
||||
int add_frame( unsigned char *buffer, size_t len);
|
||||
|
||||
int add_audio( unsigned char *buffer, size_t len);
|
||||
|
||||
int set_codec(const char *fourcc);
|
||||
|
||||
int set_size( unsigned int width, unsigned int height);
|
||||
|
||||
int set_framerate(unsigned int fps);
|
||||
|
||||
private:
|
||||
FILE *out;
|
||||
struct gwavi_header_t avi_header;
|
||||
struct gwavi_stream_header_t stream_header_v;
|
||||
struct gwavi_stream_format_v_t stream_format_v;
|
||||
struct gwavi_stream_header_t stream_header_a;
|
||||
struct gwavi_stream_format_a_t stream_format_a;
|
||||
long marker;
|
||||
int offsets_ptr;
|
||||
int offsets_len;
|
||||
long offsets_start;
|
||||
unsigned int *offsets;
|
||||
int offset_count;
|
||||
|
||||
// helper functions
|
||||
int write_avi_header(FILE *out, struct gwavi_header_t *avi_header);
|
||||
int write_stream_header(FILE *out,
|
||||
struct gwavi_stream_header_t *stream_header);
|
||||
int write_stream_format_v(FILE *out,
|
||||
struct gwavi_stream_format_v_t *stream_format_v);
|
||||
int write_stream_format_a(FILE *out,
|
||||
struct gwavi_stream_format_a_t *stream_format_a);
|
||||
int write_avi_header_chunk(void);
|
||||
int write_index(FILE *out, int count, unsigned int *offsets);
|
||||
int check_fourcc(const char *fourcc);
|
||||
int write_int(FILE *out, unsigned int n);
|
||||
int write_short(FILE *out, unsigned int n);
|
||||
int write_chars(FILE *out, const char *s);
|
||||
int write_chars_bin(FILE *out, const char *s, int count);
|
||||
|
||||
};
|
||||
|
||||
#endif /* ndef H_GWAVI */
|
||||
|
|
@ -939,8 +939,8 @@ int fceuWrapperMemoryCleanup(void)
|
|||
*/
|
||||
void
|
||||
FCEUD_Update(uint8 *XBuf,
|
||||
int32 *Buffer,
|
||||
int Count)
|
||||
int32 *Buffer,
|
||||
int Count)
|
||||
{
|
||||
int blitDone = 0;
|
||||
//extern int FCEUDnetplay;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "common/configSys.h"
|
||||
#include "Qt/sdl-video.h"
|
||||
#include "Qt/AviRecord.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
|
||||
#ifdef CREATE_AVI
|
||||
|
@ -478,7 +479,7 @@ BlitScreen(uint8 *XBuf)
|
|||
}
|
||||
nes_shm->blitUpdated = 1;
|
||||
|
||||
//guiPixelBufferReDraw();
|
||||
aviRecordAddFrame();
|
||||
|
||||
#ifdef CREATE_AVI
|
||||
{ int fps = FCEUI_GetDesiredFPS();
|
||||
|
|
Loading…
Reference in New Issue