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.
225 lines
5.7 KiB
225 lines
5.7 KiB
4 years ago
|
/*
|
||
|
* decode_yuv.c
|
||
|
*
|
||
|
* Copyright (C) Thomas Oestreich - June 2001
|
||
|
*
|
||
|
* 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 "transcode.h"
|
||
|
#include "libtc/libtc.h"
|
||
|
#include "tcinfo.h"
|
||
|
|
||
|
#include "aclib/imgconvert.h"
|
||
|
#include "ioaux.h"
|
||
|
#include "tc.h"
|
||
|
|
||
|
/*
|
||
|
* About this code:
|
||
|
*
|
||
|
* based on video_out.h, video_out.c, video_out_ppm.c
|
||
|
*
|
||
|
* Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
|
||
|
* Stripped and rearranged for transcode by
|
||
|
* Francesco Romani <fromani@gmail.com> - July 2005
|
||
|
*
|
||
|
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
|
||
|
*
|
||
|
* What?
|
||
|
* Basically, this code does only a colorspace conversion from ingress frames
|
||
|
* (YV12) to egress frames (RGB). It uses basically the same routines of libvo
|
||
|
* and old decode_yuv.c
|
||
|
*
|
||
|
* Why?
|
||
|
* decode_yuv was the one and the only transcode module which uses the main
|
||
|
* libvo routines, not the colorspace conversion ones. It not make sense to me
|
||
|
* to have an extra library just for one module, so I stripped down to minimum
|
||
|
* the libvo code used by decode_yuv.c and I moved it here.
|
||
|
* This code has only few things recalling it's ancestor, but I'm still remark
|
||
|
* it's origin.
|
||
|
*/
|
||
|
|
||
|
typedef struct vo_s {
|
||
|
// frame size
|
||
|
unsigned int width;
|
||
|
unsigned int height;
|
||
|
|
||
|
// internal frame buffers
|
||
|
uint8_t *rgb;
|
||
|
uint8_t *yuv[3];
|
||
|
} vo_t;
|
||
|
|
||
|
#define vo_convert(instp) \
|
||
|
ac_imgconvert((instp)->yuv, IMG_YUV420P, &(instp)->rgb, IMG_RGB24, \
|
||
|
(instp)->width, (instp)->height)
|
||
|
|
||
|
#define READ_PLANE(fd, V, H, plane) do { \
|
||
|
int i, bytes; \
|
||
|
\
|
||
|
for (i = 0; i < (V); i++) { \
|
||
|
bytes = tc_pread((fd), (plane) + i * (H), (H)); \
|
||
|
if (bytes != (H)) { \
|
||
|
if (bytes < 0) \
|
||
|
tc_log_error(__FILE__, "read failed: %s", strerror(errno)); \
|
||
|
return 0; \
|
||
|
} \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
/*
|
||
|
* legacy (and working :) ) code:
|
||
|
* read one YUV420P plane at time from file descriptor (pipe, usually)
|
||
|
* and store it in internal buffer
|
||
|
*/
|
||
|
static int vo_read_yuv(vo_t *vo, int fd)
|
||
|
{
|
||
|
unsigned int v = vo->height, h = vo->width;
|
||
|
|
||
|
/* Read luminance scanlines */
|
||
|
|
||
|
READ_PLANE(fd, v, h, vo->yuv[0]);
|
||
|
|
||
|
v /= 2;
|
||
|
h /= 2;
|
||
|
|
||
|
/* Read chrominance scanlines */
|
||
|
READ_PLANE(fd, v, h, vo->yuv[1]);
|
||
|
READ_PLANE(fd, v, h, vo->yuv[2]);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
#undef READ_PLANE
|
||
|
|
||
|
/*
|
||
|
* simpler than above:
|
||
|
* write the whole RGB buffer in to file descriptor (pipe, usually).
|
||
|
* WARNING: caller must ensure that RGB buffer holds valid data by
|
||
|
* invoking vo_convert *before* invoking this function
|
||
|
*/
|
||
|
static int vo_write_rgb (vo_t *vo, int fd)
|
||
|
{
|
||
|
int framesize = vo->width * vo->height * 3;
|
||
|
int bytes = tc_pwrite(fd, vo->rgb, framesize);
|
||
|
if (bytes != framesize) {
|
||
|
if (bytes < 0)
|
||
|
tc_log_error(__FILE__, "read failed: %s", strerror(errno));
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* finalize a vo structure, free()ing it's internal buffers.
|
||
|
* WARNING: DOES NOT cause a buffer flush, you must do it manually.
|
||
|
*/
|
||
|
static void vo_clean (vo_t *vo)
|
||
|
{
|
||
|
free(vo->yuv[0]);
|
||
|
free(vo->yuv[1]);
|
||
|
free(vo->yuv[2]);
|
||
|
free(vo->rgb);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* initialize a vo structure, allocate internal buffers
|
||
|
* and so on
|
||
|
*/
|
||
|
static int vo_alloc(vo_t *vo, int width, int height)
|
||
|
{
|
||
|
if (width <= 0 || height <= 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
vo->width = (unsigned int)width;
|
||
|
vo->height = (unsigned int)height;
|
||
|
|
||
|
vo->yuv[0] = tc_zalloc(width * height);
|
||
|
if (!vo->yuv[0]) {
|
||
|
tc_log_error(__FILE__, "out of memory");
|
||
|
return -1;
|
||
|
}
|
||
|
vo->yuv[1] = tc_zalloc((width/2) * (height/2));
|
||
|
if (!vo->yuv[1]) {
|
||
|
tc_log_error(__FILE__, "out of memory");
|
||
|
free(vo->yuv[0]);
|
||
|
return -1;
|
||
|
}
|
||
|
vo->yuv[2] = tc_zalloc((width/2) * (height/2));
|
||
|
if (!vo->yuv[2]) {
|
||
|
tc_log_error(__FILE__, "out of memory");
|
||
|
free(vo->yuv[0]);
|
||
|
free(vo->yuv[1]);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
vo->rgb = tc_zalloc(width * height * 3);
|
||
|
if (!vo->rgb) {
|
||
|
tc_log_error(__FILE__, "out of memory");
|
||
|
free(vo->yuv[0]);
|
||
|
free(vo->yuv[1]);
|
||
|
free(vo->yuv[2]);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------
|
||
|
*
|
||
|
* decoder thread
|
||
|
*
|
||
|
* ------------------------------------------------------------*/
|
||
|
|
||
|
void decode_yuv(decode_t *decode)
|
||
|
{
|
||
|
vo_t vo;
|
||
|
|
||
|
if (decode->width <= 0 || decode->height <= 0) {
|
||
|
tc_log_error(__FILE__, "invalid frame parameter %dx%d",
|
||
|
decode->width, decode->height);
|
||
|
import_exit(1);
|
||
|
}
|
||
|
|
||
|
vo_alloc(&vo, decode->width, decode->height);
|
||
|
|
||
|
// read frame by frame - decode into RGB - pipe to stdout
|
||
|
while (vo_read_yuv(&vo, decode->fd_in)) {
|
||
|
vo_convert(&vo);
|
||
|
vo_write_rgb(&vo, decode->fd_out);
|
||
|
}
|
||
|
|
||
|
// ends
|
||
|
vo_clean(&vo);
|
||
|
|
||
|
import_exit(0);
|
||
|
}
|
||
|
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* Local variables:
|
||
|
* c-file-style: "stroustrup"
|
||
|
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
|
||
|
* indent-tabs-mode: nil
|
||
|
* End:
|
||
|
*
|
||
|
* vim: expandtab shiftwidth=4:
|
||
|
*/
|