RetroShare/retroshare-gui/src/util/framecatcher.cpp
chrisparker126 a9ee3d92dc introduced frame catcher to channels, add framecatcher in Retroshare.pro to build it in
(only works for linux at the moment)

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3821 b45a01b8-16f6-495d-af2f-9b41ad6348cc
2010-11-19 00:47:18 +00:00

337 lines
7.1 KiB
C++

/****************************************************************
* This file is distributed under the following license:
*
* Copyright (c) 2006 Raul E.
* Copyright (c) 2010 Chris Evi-Parker
*
* This program 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.
*
* This program 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*************************************************************************/
#include "framecatcher.h"
#include <iostream>
framecatcher::framecatcher(): xine(NULL), stream(NULL), vo_port(NULL){
// start up drivers
std::string vo_driver = "auto";
xine= xine_new();
xine_init(xine);
if((vo_port=xine_open_video_driver(xine,vo_driver.c_str(),XINE_VISUAL_TYPE_NONE, NULL))==NULL)
std::cerr << "framecatcher::framecatcher() " << "ERROR OPENING VIDEO DRIVER";
}
framecatcher::~framecatcher(){
if(stream != NULL){
close();
}
xine_close_video_driver(xine,vo_port);
}
std::string framecatcher::getCodec(){
return codec;
}
int framecatcher::getLength(){
return length;
}
int framecatcher::open(const std::string& fileName){
int errorCode = 0;
/* ensure resources used previous stream have been released */
if(stream != NULL)
close();
stream = xine_stream_new(xine,NULL,vo_port);
if(stream == NULL)
return 0;
// open stream
if(!xine_open(stream,fileName.c_str())){
errorCode= xine_get_error(stream);
return errorCode;
}
// get length of video file stream is attached to
if(!xine_get_pos_length(stream,0,0,&length)){
errorCode = xine_get_error(stream);
return errorCode;
}
xine_play(stream,0,0);
const char* temp_codec=xine_get_meta_info(stream, XINE_META_INFO_VIDEOCODEC);
if(temp_codec == NULL)
return 0;
codec = temp_codec;
return 1;
}
void framecatcher::close(){
if(stream != NULL){
xine_close(stream);
xine_dispose(stream);
stream = NULL;
}
}
int framecatcher::getRGBImage(int frame, unsigned char*& rgb32BitData, int& width, int& height){
if(stream == NULL)
return 0;
int errCode = 0;
xine_play(stream,0,0);
xine_play(stream,0,frame); // 1 frame 2 mseconds
uint8_t *yuv = NULL, *y = NULL, *u = NULL, *v =NULL ;
int ratio = 0, format = 0;
if (!xine_get_current_frame(stream, &width, &height, &ratio, &format, NULL)){
errCode= xine_get_error(stream);
return errCode;
}
yuv = new uint8_t[((width+8) * (height+1) * 2)];
if (yuv == NULL){
std::cerr << "Out of Memory!";
return 0;
}
if (!xine_get_current_frame(stream, &width, &height, &ratio, &format, yuv)){
errCode= xine_get_error(stream);
if(yuv != NULL)
delete[] yuv;
return errCode;
}
/*
* convert to yv12 if necessary
*/
switch (format){
case XINE_IMGFMT_YUY2:
{
uint8_t *yuy2 = yuv;
yuv = new uint8_t[(width * height * 2)];
if (yuv == NULL){
std::cerr << "Not enough memory to make screenshot!" << std::endl;
return 0;
}
y = yuv;
u = yuv + width * height;
v = yuv + width * height * 5 / 4;
yuy2Toyv12 (y, u, v, yuy2, width, height);
delete [] yuy2;
}
break;
case XINE_IMGFMT_YV12:
y = yuv;
u = yuv + width * height;
v = yuv + width * height * 5 / 4;
break;
default:
{
std::cerr << "Format Not Supported" << std::endl;
if(yuv != NULL)
delete [] yuv;
return 0;
}
}
rgb32BitData = yv12ToRgb (y, u, v, width, height);
delete [] yuv;
return 1;
}
void framecatcher::yuy2Toyv12 (uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *input, int width, int height){
int i, j, w2;
w2 = width / 2;
for (i = 0; i < height; i += 2){
for (j = 0; j < w2; j++){
/*
* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i]
*/
*(y++) = *(input++);
*(u++) = *(input++);
*(y++) = *(input++);
*(v++) = *(input++);
}
/*
* down sampling
*/
for (j = 0; j < w2; j++){
/*
* skip every second line for U and V
*/
*(y++) = *(input++);
input++;
*(y++) = *(input++);
input++;
}
}
}
unsigned char * framecatcher::yv12ToRgb (uint8_t *src_y, uint8_t *src_u, uint8_t *src_v, int width, int height){
/*
* Create rgb data from yv12
*/
#define clip_8_bit(val) \
{ \
if (val < 0) \
val = 0; \
else \
if (val > 255) val = 255; \
}
int i, j;
int y, u, v;
int r, g, b;
int sub_i_uv;
int sub_j_uv;
int uv_width, uv_height;
unsigned char *rgb;
uv_width = width / 2;
uv_height = height / 2;
rgb = new unsigned char[(width * height * 4)]; //qt needs a 32bit align
if (!rgb) //qDebug ("Not enough memory!");
return NULL;
for (i = 0; i < height; ++i){
/*
* calculate u & v rows
*/
sub_i_uv = ((i * uv_height) / height);
for (j = 0; j < width; ++j){
/*
* calculate u & v columns
*/
sub_j_uv = ((j * uv_width) / width);
/***************************************************
*
* Colour conversion from
* http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
*
* Thanks to Billy Biggs <vektor@dumbterm.net>
* for the pointer and the following conversion.
*
* R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
* G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
* B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
*
* Where in xine the above values are represented as
*
* Y' == image->y
* Cb == image->u
* Cr == image->v
*
***************************************************/
y = src_y[(i * width) + j] - 16;
u = src_u[(sub_i_uv * uv_width) + sub_j_uv] - 128;
v = src_v[(sub_i_uv * uv_width) + sub_j_uv] - 128;
r = (int)((1.1644 * (double)y) + (1.5960 * (double)v));
g = (int)((1.1644 * (double)y) - (0.3918 * (double)u) - (0.8130 * (double)v));
b = (int)((1.1644 * (double)y) + (2.0172 * (double)u));
clip_8_bit (r);
clip_8_bit (g);
clip_8_bit (b);
rgb[(i * width + j) * 4 + 0] = b;
rgb[(i * width + j) * 4 + 1] = g;
rgb[(i * width + j) * 4 + 2] = r;
rgb[(i * width + j) * 4 + 3] = 0;
}
}
return rgb;
}
void framecatcher::getError(int errorCode, std::string& errorStr){
switch (errorCode){
case XINE_ERROR_NO_INPUT_PLUGIN:
case XINE_ERROR_NO_DEMUX_PLUGIN: {
errorStr = "No plugin found to handle this resource";
break;
}
case XINE_ERROR_DEMUX_FAILED: {
errorStr = "Resource seems to be broken";
break;
}
case XINE_ERROR_MALFORMED_MRL: {
errorStr = "Requested resource does not exist";
break;
}
case XINE_ERROR_INPUT_FAILED: {
errorStr = "Resource can not be opened";
break;
}
default: {
errorStr = "Unknown error";
break;
}
}
return;
}