From cb4f44ea39f43dce77c928c384225aba93b38c19 Mon Sep 17 00:00:00 2001 From: chrisparker126 Date: Sat, 13 Nov 2010 19:08:05 +0000 Subject: [PATCH] framecatcher utility for capturing frames from videos (libxine dependency) - initial ci git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3787 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- retroshare-gui/src/util/filefunctions.cpp | 373 ++++++++++++++++++++++ retroshare-gui/src/util/filefunctions.h | 67 ++++ 2 files changed, 440 insertions(+) create mode 100644 retroshare-gui/src/util/filefunctions.cpp create mode 100644 retroshare-gui/src/util/filefunctions.h diff --git a/retroshare-gui/src/util/filefunctions.cpp b/retroshare-gui/src/util/filefunctions.cpp new file mode 100644 index 000000000..f309ccb20 --- /dev/null +++ b/retroshare-gui/src/util/filefunctions.cpp @@ -0,0 +1,373 @@ +/**************************************************************** + * This file is distributed under the following license: + * + * Copyright (c) 2006 Raul E. + * Copyright (c) 2010 Christopher 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 "filefunctions.h" + +QString filefunctions::cfilename=NULL; +QTreeWidget *filefunctions::treeObj=NULL; +QStringList filefunctions::tempimages; +QString filefunctions::codec=NULL; +int filefunctions::length=0; +int filefunctions::fwidth=0; +int filefunctions::fheight=0; + +filefunctions::filefunctions(){ + +// clear tempfiles +for ( int i=0; isave(&buffer, "PNG"); +} +bool filefunctions::saveimage(const QByteArray &ba , const QString &filename){ +bool correct=true; +QFile image(filename); +if(!image.open(QIODevice::WriteOnly) ) +return false; + +if(image.write(ba)==-1) +correct=false; + +image.close(); +return correct; +} +void filefunctions::getFramesTime(){ +xine_play(stream,0,0); +codec=xine_get_meta_info(stream, XINE_META_INFO_VIDEOCODEC); + +const uint32_t chunk= (30) * 1000; // mseconds + + +// Progress Dialog +QString progresdialogtext =QApplication::translate("xine","Generating Thumbnails...",0,QApplication::UnicodeUTF8); +QString cancelbuttontext=QApplication::translate("xine","&Cancel",0,QApplication::UnicodeUTF8); + +progress = new QProgressDialog(progresdialogtext , cancelbuttontext , 0, length,0,Qt::WindowSystemMenuHint); + + +for (int32_t frame=chunk ; framesetValue(frame); +qApp->processEvents(); +if(progress->wasCanceled()) + break; +} +progress->setValue(length); +delete progress; +} +void filefunctions::getFrames(){ +xine_play(stream,0,0); +codec=xine_get_meta_info(stream, XINE_META_INFO_VIDEOCODEC); + +int frame = 20; + +xine_play(stream,0,frame); // 1 frame 2 mseconds +SaveFrame(frame); + +} + +void filefunctions::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++; + } + } +} +uchar * filefunctions::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; + + uchar *rgb; + + uv_width = width / 2; + uv_height = height / 2; + + rgb = new uchar[(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 + * 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 filefunctions::SaveFrame(int pos){ + + uint8_t *yuv = NULL, *y = NULL, *u = NULL, *v =NULL ; + + int width, height, ratio, format; + + // double desired_ratio, image_ratio; + + if (!xine_get_current_frame(stream, &width, &height, &ratio, &format, NULL)) + return; + + yuv = new uint8_t[((width+8) * (height+1) * 2)]; + if (yuv == NULL){ + qWarning("Not enough memory to make screenshot!"); + return; + } + + xine_get_current_frame(stream, &width, &height, &ratio, &format, yuv); + fwidth=width; + fheight=height; + + /* + * 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){ + qWarning("Not enough memory to make screenshot!"); + return; + } + y = yuv; + u = yuv + width * height; + v = yuv + width * height * 5 / 4; + + yuy2Toyv12 (y, u, v, yuy2, width, height); + + delete [] yuy2; + //free (yuy2); + } + break; + case XINE_IMGFMT_YV12: + y = yuv; + u = yuv + width * height; + v = yuv + width * height * 5 / 4; + + break; + default: + { + qWarning("Screenshot: Format %s not supported!",(char *) &format); + delete [] yuv; + return; + } +} +uchar* rgb32BitData = yv12ToRgb (y, u, v, width, height); +delete [] yuv; +saveRGBImage(rgb32BitData,pos,width,height); +} +QTime filefunctions::postime(const int itime){ + QTime time(0,0,0); + time=time.addMSecs(itime); + return time; +} +QString filefunctions::getXineError(int errorCode){ +QString error; +switch (errorCode){ + case XINE_ERROR_NO_INPUT_PLUGIN: + case XINE_ERROR_NO_DEMUX_PLUGIN: { + error = QApplication::translate("xine","No plugin found to handle this resource",0,QApplication::UnicodeUTF8); + break; + } + case XINE_ERROR_DEMUX_FAILED: { + error = QApplication::translate("xine","Resource seems to be broken",0,QApplication::UnicodeUTF8); + break; + } + case XINE_ERROR_MALFORMED_MRL: { + error = QApplication::translate("xine","Requested resource does not exist",0,QApplication::UnicodeUTF8); + break; + } + case XINE_ERROR_INPUT_FAILED: { + error = QApplication::translate("xine","Resource can not be opened",0,QApplication::UnicodeUTF8); + break; + } + default: { + error = QApplication::translate("xine","Unknown error",0,QApplication::UnicodeUTF8); + break; + } + } +return error; +} diff --git a/retroshare-gui/src/util/filefunctions.h b/retroshare-gui/src/util/filefunctions.h new file mode 100644 index 000000000..9b97dce08 --- /dev/null +++ b/retroshare-gui/src/util/filefunctions.h @@ -0,0 +1,67 @@ +#ifndef FILEFUNCTIONS_H +#define FILEFUNCTIONS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class filefunctions{ + +private: +xine_t *xine; +xine_stream_t *stream; +xine_video_port_t *vo_port; +xine_audio_port_t *ao_port; +xine_event_queue_t *event_queue; +char *vo_driver; +char *ao_driver; + +QString tempdir; + +static QString codec; +static int length; // length of the stream +static int fwidth; +static int fheight; +void saveRGBImage(uchar *,int,int,int); +QString getXineError(int); +QProgressDialog *progress; +void savebuffer(QByteArray &, QImage *); +bool saveimage(const QByteArray & , const QString &); + +public: +filefunctions(); +~filefunctions(); +static QString cfilename; +static QTreeWidget *treeObj; +static QStringList tempimages; +QImage* currImage; + +static QString getCodec(); +static QString getImageWidth(); +static QString getImageHeight(); +static int getLength(); + +void open(); +void getFrames(); +void getFramesTime(); + +void yuy2Toyv12 (uint8_t *, uint8_t *, uint8_t *, uint8_t *, int , int ); +uchar * yv12ToRgb (uint8_t *, uint8_t *, uint8_t *, int , int ); +void SaveFrame(int); +QTime postime(const int); + +}; +#endif