mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
a9ee3d92dc
(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
337 lines
7.1 KiB
C++
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;
|
|
}
|