@ -35,6 +35,7 @@
# include <tdeparts/genericfactory.h>
# include <tdeglobalsettings.h>
# include <tdeio/netaccess.h>
# include <tdeapplication.h>
# include <kstandarddirs.h>
# include <tdemessagebox.h>
# include <tdefiledialog.h>
@ -45,6 +46,9 @@
# include <tdetoolbar.h>
# include <tdeglobal.h>
# include <kiconloader.h>
# include <dcopclient.h>
# include <tdetempfile.h>
# include <kimageio.h>
# include <kdebug.h>
// Kaffeine
@ -180,6 +184,8 @@ void MpvPart::initActions()
new KWidgetAction ( m_volume , i18n ( " Volume " ) , 0 , 0 , 0 , actionCollection ( ) , " player_volume " ) ;
/*** Stream recording toolbar ***/
new TDEAction ( i18n ( " Take Screenshot " ) , " ksnapshot " , Key_S , this , SLOT ( slotShot ( ) ) , actionCollection ( ) , " record_shot " ) ;
m_recordAction = new TDEToggleAction ( i18n ( " &Record stream " ) , " player_record " , Key_R , this , SLOT ( slotToggleRecording ( ) ) , actionCollection ( ) , " record_toggle " ) ;
new TDEAction ( i18n ( " Set recording file " ) , " document-open " , 0 , this , SLOT ( slotSetRecordingFile ( ) ) , actionCollection ( ) , " record_open " ) ;
m_recordFile = new TQLabel ( 0 ) ;
@ -753,4 +759,159 @@ void MpvPart::hideContextMenu() {
}
}
# define THROW_ERROR(msg, details) \
kdError ( ) < < " mpv: " < < msg < < " ( " < < details < < " ) " < < endl ; \
KMessageBox : : detailedError ( nullptr , i18n ( msg ) , details ) ; \
# define THROW_ERROR_FREE(msg, details) \
THROW_ERROR ( msg , details ) \
mpv_free_node_contents ( & result ) ;
void MpvPart : : slotShot ( ) {
mpv_node result ;
int w , h , stride ;
char * format ;
mpv_byte_array * data ;
// Get screenshot as raw data in memory
const char * args [ ] = { " screenshot-raw " , nullptr } ;
if ( ! mpv_command_ret ( m_mpv , args , & result ) = = MPV_ERROR_SUCCESS ) {
THROW_ERROR ( " Internal error " , " screenshot-raw command failed " )
return ;
}
if ( result . format ! = MPV_FORMAT_NODE_MAP ) {
THROW_ERROR ( " Internal error " , " screenshot-raw command returned wrong data format " )
return ;
}
// Validate the result returned by `screenshot-raw`
# define CHECK_ARG(index, key) \
if ( qstrcmp ( result . u . list - > keys [ index ] , key ) ! = 0 ) { \
TQString error = TQString ( " screenshot-raw returned wrong argument at #%1: %2 " ) \
. arg ( index ) . arg ( key ) ; \
THROW_ERROR_FREE ( " Internal error " , error ) \
return ; \
}
CHECK_ARG ( 0 , " w " )
w = result . u . list - > values [ 0 ] . u . int64 ;
CHECK_ARG ( 1 , " h " )
h = result . u . list - > values [ 1 ] . u . int64 ;
CHECK_ARG ( 2 , " stride " )
stride = result . u . list - > values [ 2 ] . u . int64 ;
CHECK_ARG ( 3 , " format " )
format = result . u . list - > values [ 3 ] . u . string ;
CHECK_ARG ( 4 , " data " )
data = result . u . list - > values [ 4 ] . u . ba ;
# undef CHECK_ARG
// Validate image format (we can handle only bgr0, which is the default anyway)
kdDebug ( ) < < " mpv: screenshot-raw image format: " < < format < < endl ;
if ( qstrcmp ( format , " bgr0 " ) ! = 0 ) {
THROW_ERROR_FREE ( " Internal error " , " mpv: screenshot-raw returned image format other than bgr0 " )
return ;
}
// An empty image is useless but not a fatal error
if ( w < = 0 | | h < = 0 ) {
kdWarning ( ) < < " mpv: screenshot-raw returned empty image " < < endl ;
}
// Create a TQDataStream to easily read the raw image data
TQByteArray ba ;
ba . setRawData ( static_cast < char * > ( data - > data ) , data - > size ) ;
TQDataStream s ( ba , IO_ReadOnly ) ;
s . setByteOrder ( TQDataStream : : BigEndian ) ;
// Create image from raw B8G8R8X8 data
TQImage img ( w , h , 32 ) ;
for ( uint y = 0 ; y < h ; + + y ) {
TQRgb * scanline = ( TQRgb * ) img . scanLine ( y ) ;
for ( uint x = 0 ; x < w ; x + + ) {
uchar r , g , b , z ;
s > > b > > g > > r > > z ;
scanline [ x ] = tqRgb ( r , g , b ) ;
}
}
// Try to launch ksnapshot
TQString ksError ;
TQCString ksDcop ;
int ksSuccess = kapp - > startServiceByDesktopName ( " ksnapshot " , TQString : : null ,
& ksError , & ksDcop ) ;
if ( ksSuccess = = 0 ) {
// Serialize the image to pass via dcop
TQByteArray pix ;
TQDataStream ds ( pix , IO_WriteOnly ) ;
ds < < img ;
// Send the serialized image to the newly initialized ksnapshot instance
if ( ! kapp - > dcopClient ( ) - > send ( ksDcop , " interface " , " setPixmap(TQPixmap) " , pix ) ) {
THROW_ERROR ( " Unable to launch KSnapshot! " , i18n ( " You seem to be using an incompatible version of KSnapshot. " ) ) ;
return ;
}
}
else {
TQStringList mimeTypes = KImageIO : : mimeTypes ( KImageIO : : Writing ) ;
if ( mimeTypes . isEmpty ( ) ) {
THROW_ERROR ( " No image formats supported! " , " KImageIO does not support any image format for export. " ) ;
return ;
}
KFileDialog * saveDlg = new KFileDialog ( TQString : : null , TQString : : null ,
widget ( ) , " screenshotSaver " , false ) ;
saveDlg - > setOperationMode ( KFileDialog : : Saving ) ;
saveDlg - > setMimeFilter ( mimeTypes ) ;
if ( ! saveDlg - > exec ( ) ) {
return ;
}
KURL saveURL = saveDlg - > selectedURL ( ) ;
if ( saveURL . isEmpty ( ) ) return ;
TQString type = KImageIO : : type ( saveURL . url ( ) ) ;
if ( ! KImageIO : : canWrite ( type ) ) {
THROW_ERROR ( " Cannot write image " , " Format " + type + " is unsupported for export. " )
return ;
}
if ( saveURL . isLocalFile ( ) ) {
if ( ! img . save ( saveURL . path ( ) , type . latin1 ( ) ) ) {
THROW_ERROR ( " I/O Error " , " Could not save file! " )
return ;
}
}
else {
KTempFile tempFile ;
tempFile . setAutoDelete ( true ) ;
TQString tempFileName = tempFile . name ( ) ;
if ( tempFileName . isEmpty ( ) ) {
THROW_ERROR ( " I/O Error " , " Could not create temporary file! " )
return ;
}
if ( ! img . save ( tempFileName , type . latin1 ( ) ) ) {
THROW_ERROR ( " I/O Error " , " Could not write to temporary file! " )
return ;
}
if ( ! TDEIO : : NetAccess : : upload ( tempFileName , saveURL , widget ( ) ) ) {
THROW_ERROR ( " Upload error " , " Could not upload image. " )
return ;
}
}
}
}
# undef THROW_ERROR
# undef THROW_ERROR_FREE
# include "libmpv_part.moc"