You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
7.7 KiB

/*
* rawsource.c -- (almost) raw source reader interface for encoder
* expect WAV audio and YUV4MPEG2 video
* (C) 2006-2010 - Francesco Romani <fromani at gmail dot com>
*
* This file is part of transcode, a video stream processing tool.
*
* transcode 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.
*
* transcode 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "framebuffer.h"
#include "dl_loader.h"
#include "rawsource.h"
#include "libtc/libtc.h"
#include "libtc/tcframes.h"
#include "avilib/wavlib.h"
#include "rawsource.h"
#define RAWSOURCE_IM_MOD "yuv4mpeg"
static int rawsource_read_video(TCEncoderBuffer *buf, vob_t *vob);
static int rawsource_read_audio(TCEncoderBuffer *buf, vob_t *vob);
static void rawsource_dummy(TCEncoderBuffer *buf);
typedef struct tcrawsource_ {
void *im_handle;
transfer_t im_para;
int eof_flag;
int sources;
vframe_list_t *vframe;
aframe_list_t *aframe;
int acount;
} TCFileSource;
static TCFileSource rawsource = {
.im_handle = NULL,
.eof_flag = TC_FALSE,
.sources = 0,
.vframe = NULL,
.aframe = NULL,
.acount = 0,
};
static TCEncoderBuffer raw_buffer = {
.frame_id = 0,
.vptr = NULL,
.aptr = NULL,
.acquire_video_frame = rawsource_read_video,
.acquire_audio_frame = rawsource_read_audio,
.dispose_video_frame = rawsource_dummy,
.dispose_audio_frame = rawsource_dummy,
};
TCEncoderBuffer *tc_rawsource_buffer = NULL;
static int rawsource_read_video(TCEncoderBuffer *buf, vob_t *vob)
{
int ret;
if (!buf) {
/* paranoia */
return -1;
}
if (vob->im_v_size > rawsource.vframe->video_size) {
/* paranoia */
tc_log_error(__FILE__, "video buffer too small"
" (this should'nt happen)");
return -1;
}
rawsource.im_para.buffer = rawsource.vframe->video_buf;
rawsource.im_para.buffer2 = NULL;
rawsource.im_para.size = vob->im_v_size;
rawsource.im_para.flag = TC_VIDEO;
ret = tcv_import(TC_IMPORT_DECODE, &rawsource.im_para, vob);
if (ret != TC_IMPORT_OK) {
/* read failed */
rawsource.eof_flag = TC_TRUE;
return -1;
}
rawsource.vframe->video_size = rawsource.im_para.size;
rawsource.vframe->attributes = rawsource.im_para.attributes;
raw_buffer.vptr = rawsource.vframe;
raw_buffer.frame_id++;
return 0;
}
static int rawsource_read_audio(TCEncoderBuffer *buf, vob_t *vob)
{
int ret = 0;
int abytes = vob->im_a_size;
// audio adjustment for non PAL frame rates:
if (rawsource.acount != 0 && rawsource.acount % TC_LEAP_FRAME == 0) {
abytes += vob->a_leap_bytes;
}
if (!buf) {
/* paranoia */
return -1;
}
if (abytes > rawsource.aframe->audio_size) {
/* paranoia */
tc_log_error(__FILE__, "audio buffer too small"
" (this should'nt happen)");
return -1;
}
rawsource.im_para.buffer = rawsource.aframe->audio_buf;
rawsource.im_para.buffer2 = NULL;
rawsource.im_para.size = abytes;
rawsource.im_para.flag = TC_AUDIO;
ret = tca_import(TC_IMPORT_DECODE, &rawsource.im_para, vob);
if (ret != TC_IMPORT_OK) {
/* read failed */
rawsource.eof_flag = TC_TRUE;
return -1;
}
rawsource.acount++;
rawsource.aframe->audio_size = rawsource.im_para.size;
rawsource.aframe->attributes = rawsource.im_para.attributes;
raw_buffer.aptr = rawsource.aframe;
return 0;
}
static void rawsource_dummy(TCEncoderBuffer *buf)
{
return;
}
int tc_rawsource_open(vob_t *vob)
{
int ret = 0;
int num_sources = 0;
double samples;
if (!vob) {
goto vframe_failed;
}
rawsource.vframe = tc_new_video_frame(vob->im_v_width, vob->im_v_height,
vob->im_v_codec, TC_TRUE);
if (!rawsource.vframe) {
tc_log_error(__FILE__, "can't allocate video frame buffer");
goto vframe_failed;
}
samples = TC_AUDIO_SAMPLES_IN_FRAME(vob->a_rate, vob->ex_fps);
rawsource.aframe = tc_new_audio_frame(samples, vob->a_chan, vob->a_bits);
if (!rawsource.aframe) {
tc_log_error(__FILE__, "can't allocate audio frame buffer");
goto aframe_failed;
}
rawsource.im_handle = load_module(RAWSOURCE_IM_MOD, TC_IMPORT|TC_AUDIO|TC_VIDEO);
if (!rawsource.im_handle) {
tc_log_error(__FILE__, "can't load import module");
goto load_failed;
}
/* hello, module! */
memset(&rawsource.im_para, 0, sizeof(transfer_t));
rawsource.im_para.flag = vob->verbose;
tca_import(TC_IMPORT_NAME, &rawsource.im_para, NULL);
memset(&rawsource.im_para, 0, sizeof(transfer_t));
rawsource.im_para.flag = vob->verbose;
tcv_import(TC_IMPORT_NAME, &rawsource.im_para, NULL);
/* open sources */
memset(&rawsource.im_para, 0, sizeof(transfer_t));
rawsource.im_para.flag = TC_AUDIO;
ret = tca_import(TC_IMPORT_OPEN, &rawsource.im_para, vob);
if (TC_IMPORT_OK == ret) {
num_sources++;
rawsource.sources |= TC_AUDIO;
}
memset(&rawsource.im_para, 0, sizeof(transfer_t));
rawsource.im_para.flag = TC_VIDEO;
ret = tcv_import(TC_IMPORT_OPEN, &rawsource.im_para, vob);
if (TC_IMPORT_OK == ret) {
num_sources++;
rawsource.sources |= TC_VIDEO;
}
if (num_sources > 0) {
tc_rawsource_buffer = &raw_buffer;
}
return num_sources;
load_failed:
tc_del_audio_frame(rawsource.aframe);
aframe_failed:
tc_del_video_frame(rawsource.vframe);
vframe_failed:
return -1;
}
static void tc_rawsource_free(void)
{
if (rawsource.vframe != NULL) {
tc_del_video_frame(rawsource.vframe);
rawsource.vframe = NULL;
}
if (rawsource.aframe != NULL) {
tc_del_audio_frame(rawsource.aframe);
rawsource.aframe = NULL;
}
}
/* errors not fatal, but notified */
int tc_rawsource_close(void)
{
tc_rawsource_free();
if (rawsource.im_handle != NULL) {
int ret = 0;
memset(&rawsource.im_para, 0, sizeof(transfer_t));
rawsource.im_para.flag = TC_VIDEO;
ret = tcv_import(TC_IMPORT_CLOSE, &rawsource.im_para, NULL);
if(ret != TC_IMPORT_OK) {
tc_log_warn(__FILE__, "video import module error: CLOSE failed");
} else {
rawsource.sources &= ~TC_VIDEO;
}
memset(&rawsource.im_para, 0, sizeof(transfer_t));
rawsource.im_para.flag = TC_AUDIO;
ret = tca_import(TC_IMPORT_CLOSE, &rawsource.im_para, NULL);
if(ret != TC_IMPORT_OK) {
tc_log_warn(__FILE__, "audio import module error: CLOSE failed");
} else {
rawsource.sources &= ~TC_AUDIO;
}
if (!rawsource.sources) {
unload_module(rawsource.im_handle);
rawsource.im_handle = NULL;
}
}
return 0;
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/