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.

277 lines
7.5 KiB

/*
* extract_yuv.c
*
* Copyright (C) Thomas Oestreich - June 2001
* Copyright (C) Francesco Romani - March 2006
*
* 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, 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 GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "config.h"
#include "transcode.h"
#include "framebuffer.h"
#include "tcinfo.h"
#include "libtc/libtc.h"
#include "libtc/ratiocodes.h"
#include "libtc/tcframes.h"
#include "ioaux.h"
#include "avilib/avilib.h"
#include "tc.h"
#if defined HAVE_MJPEGTOOLS
/* assert using new code (FIXME?) */
#if defined(HAVE_MJPEGTOOLS_INC)
#include "yuv4mpeg.h"
#include "mpegconsts.h"
#else
#include "mjpegtools/yuv4mpeg.h"
#include "mjpegtools/mpegconsts.h"
#endif
/* ------------------------------------------------------------
*
* yuv extract thread
*
* magic: TC_MAGIC_YUV4MPEG
* TC_MAGIC_RAW <-- default
*
*
* ------------------------------------------------------------*/
static int extract_yuv_y4m(info_t *ipipe)
{
vframe_list_t *vptr = NULL;
uint8_t *planes[3];
int planesize[3];
int ch_mode, w, h, ret = 0, i = 0, errnum;
y4m_frame_info_t frameinfo;
y4m_stream_info_t streaminfo;
/* initialize stream-information */
y4m_accept_extensions(1);
y4m_init_stream_info(&streaminfo);
y4m_init_frame_info(&frameinfo);
errnum = y4m_read_stream_header(ipipe->fd_in, &streaminfo);
if (errnum != Y4M_OK) {
tc_log_error(__FILE__, "Couldn't read YUV4MPEG header: %s!",
y4m_strerr (errnum));
return 1;
}
if (y4m_si_get_plane_count(&streaminfo) != 3) {
tc_log_error(__FILE__, "Only 3-plane formats supported");
return 1;
}
ch_mode = y4m_si_get_chroma(&streaminfo);
if (ch_mode != Y4M_CHROMA_420JPEG && ch_mode != Y4M_CHROMA_420MPEG2
&& ch_mode != Y4M_CHROMA_420PALDV) {
tc_log_error(__FILE__, "sorry, chroma mode `%s' (%i) not supported",
y4m_chroma_description(ch_mode), ch_mode);
return 1;
}
w = y4m_si_get_width(&streaminfo);
h = y4m_si_get_height(&streaminfo);
vptr = tc_new_video_frame(w, h, TC_CODEC_YUV420P, TC_TRUE);
if (!vptr) {
tc_log_error(__FILE__, "can't allocate buffer (%ix%i)", w, h);
return 1;
}
planes[0] = vptr->video_buf_Y[0];
planes[1] = vptr->video_buf_U[0];
planes[2] = vptr->video_buf_V[0];
planesize[0] = y4m_si_get_plane_length(&streaminfo, 0);
planesize[1] = y4m_si_get_plane_length(&streaminfo, 1);
planesize[2] = y4m_si_get_plane_length(&streaminfo, 2);
while (1) {
errnum = y4m_read_frame(ipipe->fd_in, &streaminfo, &frameinfo, planes);
if (errnum != Y4M_OK) {
break;
}
for (i = 0; i < 3; i++) {
ret = tc_pwrite(ipipe->fd_out, planes[i], planesize[i]);
if (ret != planesize[i]) {
tc_log_perror(__FILE__, "error while writing output data");
break;
}
}
}
tc_del_video_frame(vptr);
y4m_fini_frame_info(&frameinfo);
y4m_fini_stream_info(&streaminfo);
return 0;
}
static int extract_yuv_avi(info_t *ipipe)
{
avi_t *avifile=NULL;
char *video;
int key;
long frames, bytes, n;
if (ipipe->nav_seek_file) {
avifile = AVI_open_indexfd(ipipe->fd_in, 0, ipipe->nav_seek_file);
} else {
avifile = AVI_open_fd(ipipe->fd_in, 1);
}
if (NULL == avifile) {
AVI_print_error("AVI open");
return 1;
}
// read video info;
frames = AVI_video_frames(avifile);
if (ipipe->frame_limit[1] < frames) {
frames=ipipe->frame_limit[1];
}
if (ipipe->verbose & TC_STATS) {
tc_log_info(__FILE__, "%ld video frames", frames);
}
// allocate space, assume max buffer size
video = tc_bufalloc(SIZE_RGB_FRAME);
if (video == NULL) {
tc_log_error(__FILE__, "out of memory");
return 1;
}
AVI_set_video_position(avifile, ipipe->frame_limit[0]);
for (n = ipipe->frame_limit[0]; n <= frames; ++n) {
bytes = AVI_read_frame(avifile, video, &key);
if (bytes < 0) {
return 1;
}
if (tc_pwrite(ipipe->fd_out, video, bytes) != bytes) {
tc_log_perror(__FILE__, "error while writing output data");
return 1;
}
}
tc_buffree(video);
return 0;
}
static int extract_yuv_raw(info_t *ipipe)
{
if (ipipe->magic == TC_MAGIC_UNKNOWN) {
tc_log_warn(__FILE__, "no file type specified, assuming (%s)",
filetype(TC_MAGIC_RAW));
}
return tc_preadwrite(ipipe->fd_in, ipipe->fd_out);
}
void extract_yuv(info_t *ipipe)
{
int error = 0;
switch(ipipe->magic) {
case TC_MAGIC_YUV4MPEG:
error = extract_yuv_y4m(ipipe);
break;
case TC_MAGIC_AVI:
error = extract_yuv_avi(ipipe);
break;
case TC_MAGIC_RAW:
default:
error = extract_yuv_raw(ipipe);
break;
}
if (error) {
tc_log_error(__FILE__, "write failed");
import_exit(error);
}
}
void probe_yuv(info_t *ipipe)
{
int errnum = Y4M_OK;
y4m_frame_info_t frameinfo;
y4m_stream_info_t streaminfo;
y4m_ratio_t r;
/* initialize stream-information */
y4m_accept_extensions(1);
y4m_init_stream_info(&streaminfo);
y4m_init_frame_info(&frameinfo);
errnum = y4m_read_stream_header(ipipe->fd_in, &streaminfo);
if (errnum != Y4M_OK) {
tc_log_error(__FILE__, "Couldn't read YUV4MPEG header: %s!",
y4m_strerr(errnum));
import_exit(1);
}
ipipe->probe_info->width = y4m_si_get_width(&streaminfo);
ipipe->probe_info->height = y4m_si_get_height(&streaminfo);
r = y4m_si_get_framerate(&streaminfo);
ipipe->probe_info->fps = (double)r.n / (double)r.d;
tc_frc_code_from_ratio(&(ipipe->probe_info->frc), r.n, r.d);
r = y4m_si_get_sampleaspect(&streaminfo);
tc_asr_code_from_ratio(&(ipipe->probe_info->asr), r.n, r.d);
ipipe->probe_info->codec=TC_CODEC_YUV420P;
ipipe->probe_info->magic=TC_MAGIC_YUV4MPEG;
y4m_fini_frame_info(&frameinfo);
y4m_fini_stream_info(&streaminfo);
}
#else /* HAVE_MJPEGTOOLS */
void extract_yuv(info_t *ipipe)
{
tc_log_error(__FILE__, "No support for YUV4MPEG compiled in.");
tc_log_error(__FILE__, "Recompile with mjpegtools support enabled.");
import_exit(1);
}
void probe_yuv(info_t * ipipe)
{
tc_log_error(__FILE__, "No support for YUV4MPEG compiled in.");
tc_log_error(__FILE__, "Recompile with mjpegtools support enabled.");
ipipe->probe_info->codec = TC_CODEC_UNKNOWN;
ipipe->probe_info->magic = TC_MAGIC_UNKNOWN;
}
#endif /* HAVE_MJPEGTOOLS */
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/