opencv/modules/videoio/src/cap_xine.cpp

356 lines
11 KiB
C++
Raw Normal View History

2018-04-20 17:30:54 +08:00
/*M//////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
// Authors: Konstantin Dols <dols@ient.rwth-aachen.de>
// Mark Asbach <asbach@ient.rwth-aachen.de>
//
// Institute of Communications Engineering
// RWTH Aachen University
#include "precomp.hpp"
// required to enable some functions used here...
#define XINE_ENABLE_EXPERIMENTAL_FEATURES
#include <xine.h>
2018-04-20 17:30:54 +08:00
#include <xine/xineutils.h>
2018-04-20 17:30:54 +08:00
using namespace cv;
2018-04-20 17:30:54 +08:00
class XINECapture : public IVideoCapture
{
2018-04-20 17:30:54 +08:00
// method call table
xine_t *xine;
xine_stream_t *stream;
xine_video_port_t *vo_port;
2012-10-17 15:12:04 +08:00
xine_video_frame_t xine_frame;
2018-04-20 17:30:54 +08:00
Size size;
int frame_number;
double frame_rate; // fps
double frame_duration; // ms
bool seekable;
public:
XINECapture()
: xine(0), stream(0), vo_port(0), frame_number(-1), frame_rate(0.), frame_duration(0.),
seekable(false)
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
xine_video_frame_t z = {};
xine_frame = z;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
~XINECapture() { close(); }
2018-04-20 17:30:54 +08:00
bool isOpened() const CV_OVERRIDE { return xine && stream; }
2012-10-17 15:12:04 +08:00
2018-04-20 17:30:54 +08:00
int getCaptureDomain() CV_OVERRIDE { return CAP_XINE; }
2012-10-17 15:12:04 +08:00
2018-04-20 17:30:54 +08:00
void close()
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
if (vo_port && xine_frame.data)
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
xine_free_video_frame(vo_port, &xine_frame);
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
if (stream)
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
xine_close(stream);
stream = 0;
}
if (vo_port)
{
xine_close_video_driver(xine, vo_port);
vo_port = 0;
}
if (xine)
{
xine_exit(xine);
xine = 0;
2012-10-17 15:12:04 +08:00
}
}
2018-04-20 17:30:54 +08:00
bool open(const char *filename)
{
CV_Assert_N(!xine, !stream, !vo_port);
2018-04-20 17:30:54 +08:00
char configfile[2048] = {0};
2018-04-20 17:30:54 +08:00
xine = xine_new();
sprintf(configfile, "%s%s", xine_get_homedir(), "/.xine/config");
xine_config_load(xine, configfile);
xine_init(xine);
xine_engine_set_param(xine, 0, 0);
2018-04-20 17:30:54 +08:00
vo_port = xine_new_framegrab_video_port(xine);
if (!vo_port)
return false;
2018-04-20 17:30:54 +08:00
stream = xine_stream_new(xine, NULL, vo_port);
if (!xine_open(stream, filename))
return false;
2018-04-20 17:30:54 +08:00
// reset stream...
if (!xine_play(stream, 0, 0))
return false;
2018-04-20 17:30:54 +08:00
// initialize some internals...
frame_number = 0;
2018-04-20 17:30:54 +08:00
if ( !xine_get_next_video_frame( vo_port, &xine_frame ) )
return false;
2018-04-20 17:30:54 +08:00
size = Size( xine_frame.width, xine_frame.height );
2018-04-20 17:30:54 +08:00
xine_free_video_frame( vo_port, &xine_frame );
xine_frame.data = 0;
2018-04-20 17:30:54 +08:00
{
xine_video_frame_t tmp;
if (!xine_play( stream, 0, 300 )) /* 300msec */
return false;
if (!xine_get_next_video_frame( vo_port, &tmp ))
return false;
seekable = ( tmp.frame_number != 0 );
xine_free_video_frame( vo_port, &tmp );
if (!xine_play( stream, 0, 0 ))
return false;
}
2018-04-20 17:30:54 +08:00
frame_duration = xine_get_stream_info( stream, XINE_STREAM_INFO_FRAME_DURATION ) / 90.;
frame_rate = frame_duration > 0 ? 1000 / frame_duration : 0.;
return true;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
bool grabFrame() CV_OVERRIDE
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
CV_Assert(vo_port);
bool res = xine_get_next_video_frame(vo_port, &xine_frame);
if (res)
frame_number++;
return res;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
bool retrieveFrame(int, OutputArray out) CV_OVERRIDE
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
CV_Assert(stream);
CV_Assert(vo_port);
2018-04-20 17:30:54 +08:00
if (xine_frame.data == 0)
return false;
2018-04-20 17:30:54 +08:00
bool res = false;
Mat frame_bgr;
2018-04-20 17:30:54 +08:00
switch (xine_frame.colorspace)
{
case XINE_IMGFMT_YV12: // actual format seems to be I420 (or IYUV)
{
Mat frame(Size(xine_frame.width, xine_frame.height * 3 / 2), CV_8UC1, xine_frame.data);
cv::cvtColor(frame, out, cv::COLOR_YUV2BGR_I420);
res = true;
}
break;
2018-04-20 17:30:54 +08:00
case XINE_IMGFMT_YUY2:
{
Mat frame(Size(xine_frame.width, xine_frame.height), CV_8UC2, xine_frame.data);
cv::cvtColor(frame, out, cv::COLOR_YUV2BGR_YUY2);
res = true;
}
break;
2018-04-20 17:30:54 +08:00
default:
break;
}
2018-04-20 17:30:54 +08:00
// always release last xine_frame, not needed anymore
xine_free_video_frame(vo_port, &xine_frame);
xine_frame.data = 0;
return res;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
double getProperty(int property_id) const CV_OVERRIDE
2012-10-17 15:12:04 +08:00
{
CV_Assert_N(xine, vo_port, stream);
2018-04-20 17:30:54 +08:00
int pos_t, pos_l, length;
bool res = (bool)xine_get_pos_length(stream, &pos_l, &pos_t, &length);
switch (property_id)
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
case CV_CAP_PROP_POS_MSEC: return res ? pos_t : 0;
case CV_CAP_PROP_POS_FRAMES: return frame_number;
case CV_CAP_PROP_POS_AVI_RATIO: return length && res ? pos_l / 65535.0 : 0.0;
case CV_CAP_PROP_FRAME_WIDTH: return size.width;
case CV_CAP_PROP_FRAME_HEIGHT: return size.height;
case CV_CAP_PROP_FPS: return frame_rate;
case CV_CAP_PROP_FOURCC: return (double)xine_get_stream_info(stream, XINE_STREAM_INFO_VIDEO_FOURCC);
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
return 0;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
bool setProperty(int property_id, double value) CV_OVERRIDE
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
CV_Assert(stream);
CV_Assert(vo_port);
switch (property_id)
{
case CV_CAP_PROP_POS_MSEC: return seekTime((int)value);
case CV_CAP_PROP_POS_FRAMES: return seekFrame((int)value);
case CV_CAP_PROP_POS_AVI_RATIO: return seekRatio(value);
default: return false;
}
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
protected:
bool oldSeekFrame(int f)
2012-10-17 15:12:04 +08:00
{
CV_Assert_N(xine, vo_port, stream);
2018-04-20 17:30:54 +08:00
// no need to seek if we are already there...
if (f == frame_number)
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
return true;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
else if (f > frame_number)
{
// if the requested position is behind out actual position,
// we just need to read the remaining amount of frames until we are there.
for (; frame_number < f; frame_number++)
{
// un-increment framenumber grabbing failed
if (!xine_get_next_video_frame(vo_port, &xine_frame))
{
frame_number--;
break;
}
else
{
xine_free_video_frame(vo_port, &xine_frame);
}
}
}
else // f < frame_number
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
// otherwise we need to reset the stream and
// start reading frames from the beginning.
// reset stream, should also work with non-seekable input
xine_play(stream, 0, 0);
// read frames until we are at the requested frame
for (frame_number = 0; frame_number < f; frame_number++)
{
// un-increment last framenumber if grabbing failed
if (!xine_get_next_video_frame(vo_port, &xine_frame))
{
frame_number--;
break;
}
else
{
xine_free_video_frame(vo_port, &xine_frame);
}
}
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
return f == frame_number;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
bool seekFrame(int f)
2012-10-17 15:12:04 +08:00
{
CV_Assert_N(xine, vo_port, stream);
2018-04-20 17:30:54 +08:00
if (seekable)
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
int new_time = (int)((f + 1) * (float)frame_duration);
if (xine_play(stream, 0, new_time))
{
frame_number = f;
return true;
}
2012-10-17 15:12:04 +08:00
}
else
{
2018-04-20 17:30:54 +08:00
return oldSeekFrame(f);
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
return false;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
bool seekTime(int t)
2012-10-17 15:12:04 +08:00
{
CV_Assert_N(xine, vo_port, stream);
2018-04-20 17:30:54 +08:00
if (seekable)
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
if (xine_play(stream, 0, t))
{
frame_number = (int)((double)t * frame_rate / 1000);
return true;
}
2012-10-17 15:12:04 +08:00
}
else
{
2018-04-20 17:30:54 +08:00
int new_frame = (int)((double)t * frame_rate / 1000);
return oldSeekFrame(new_frame);
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
return false;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
bool seekRatio(double ratio)
2012-10-17 15:12:04 +08:00
{
CV_Assert_N(xine, vo_port, stream);
2018-04-20 17:30:54 +08:00
if (ratio > 1 || ratio < 0)
return false;
if (seekable)
{
// TODO: FIX IT, DOESN'T WORK PROPERLY, YET...!
int pos_t, pos_l, length;
bool res = (bool)xine_get_pos_length(stream, &pos_l, &pos_t, &length);
if (res && xine_play(stream, (int)(ratio * (double)length), 0))
2012-10-17 15:12:04 +08:00
{
2018-04-20 17:30:54 +08:00
frame_number = (int)(ratio * length / frame_duration);
return true;
2012-10-17 15:12:04 +08:00
}
2018-04-20 17:30:54 +08:00
}
return false;
2012-10-17 15:12:04 +08:00
}
};
2018-04-20 17:30:54 +08:00
Ptr<IVideoCapture> cv::createXINECapture(const char *filename)
{
2018-04-20 17:30:54 +08:00
Ptr<XINECapture> res = makePtr<XINECapture>();
if (res && res->open(filename))
return res;
return Ptr<IVideoCapture>();
}