mirror of
https://github.com/tuxbox-fork-migrations/recycled-ni-libstb-hal.git
synced 2025-08-27 07:22:44 +02:00
generic-pc: add somewhat working video decoder
Origin commit data
------------------
Branch: master
Commit: 9541c0ac1e
Author: Stefan Seyfried <seife@tuxbox-git.slipkontur.de>
Date: 2013-05-04 (Sat, 04 May 2013)
------------------
No further description and justification available within origin commit message!
------------------
This commit was generated by Migit
This commit is contained in:
@@ -15,57 +15,62 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
|
* Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
|
||||||
|
*
|
||||||
|
* cVideo implementation with decoder.
|
||||||
|
* uses ffmpeg <http://ffmpeg.org> for demuxing / decoding
|
||||||
|
* decoded frames are stored in SWFramebuffer class
|
||||||
|
*
|
||||||
|
* TODO: buffer handling surely needs some locking...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* this is a dummy implementation with no functionality at all */
|
|
||||||
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <utime.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <pthread.h>
|
extern "C" {
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ffmpeg buf 32k */
|
||||||
|
#define INBUF_SIZE 0x8000
|
||||||
|
/* my own buf 256k */
|
||||||
|
#define DMX_BUF_SZ 0x20000
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/dvb/video.h>
|
|
||||||
#include "video_lib.h"
|
#include "video_lib.h"
|
||||||
#define VIDEO_DEVICE "/dev/dvb/adapter0/video0"
|
#include "dmx_lib.h"
|
||||||
#include "lt_debug.h"
|
#include "lt_debug.h"
|
||||||
#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, this, args)
|
#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, this, args)
|
||||||
#define lt_info(args...) _lt_info(TRIPLE_DEBUG_VIDEO, this, args)
|
#define lt_info(args...) _lt_info(TRIPLE_DEBUG_VIDEO, this, args)
|
||||||
#define lt_debug_c(args...) _lt_debug(TRIPLE_DEBUG_VIDEO, NULL, args)
|
|
||||||
#define lt_info_c(args...) _lt_info(TRIPLE_DEBUG_VIDEO, NULL, args)
|
|
||||||
|
|
||||||
#define fop(cmd, args...) ({ \
|
cVideo *videoDecoder = NULL;
|
||||||
int _r; \
|
extern cDemux *videoDemux;
|
||||||
if (fd >= 0) { \
|
|
||||||
if ((_r = ::cmd(fd, args)) < 0) \
|
|
||||||
lt_info(#cmd"(fd, "#args")\n"); \
|
|
||||||
else \
|
|
||||||
lt_debug(#cmd"(fd, "#args")\n");\
|
|
||||||
} \
|
|
||||||
else { _r = fd; } \
|
|
||||||
_r; \
|
|
||||||
})
|
|
||||||
|
|
||||||
cVideo * videoDecoder = NULL;
|
|
||||||
int system_rev = 0;
|
int system_rev = 0;
|
||||||
|
|
||||||
|
static uint8_t *dmxbuf;
|
||||||
|
static int bufpos;
|
||||||
|
|
||||||
cVideo::cVideo(int, void *, void *)
|
cVideo::cVideo(int, void *, void *)
|
||||||
{
|
{
|
||||||
lt_debug("%s\n", __FUNCTION__);
|
lt_debug("%s\n", __func__);
|
||||||
|
av_register_all();
|
||||||
|
dmxbuf = (uint8_t *)malloc(DMX_BUF_SZ);
|
||||||
|
bufpos = 0;
|
||||||
|
thread_running = false;
|
||||||
|
w_h_changed = false;
|
||||||
|
dec_w = dec_h = 0;
|
||||||
|
buf_num = 0;
|
||||||
|
buf_in = 0;
|
||||||
|
buf_out = 0;
|
||||||
|
firstpts = AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
cVideo::~cVideo(void)
|
cVideo::~cVideo(void)
|
||||||
{
|
{
|
||||||
|
Stop();
|
||||||
|
/* ouch :-( */
|
||||||
|
videoDecoder = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cVideo::setAspectRatio(int, int)
|
int cVideo::setAspectRatio(int, int)
|
||||||
@@ -85,11 +90,21 @@ int cVideo::setCroppingMode(int)
|
|||||||
|
|
||||||
int cVideo::Start(void *, unsigned short, unsigned short, void *)
|
int cVideo::Start(void *, unsigned short, unsigned short, void *)
|
||||||
{
|
{
|
||||||
|
lt_info("%s running %d >\n", __func__, thread_running);
|
||||||
|
if (!thread_running)
|
||||||
|
OpenThreads::Thread::start();
|
||||||
|
lt_info("%s running %d <\n", __func__, thread_running);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cVideo::Stop(bool)
|
int cVideo::Stop(bool)
|
||||||
{
|
{
|
||||||
|
lt_info("%s running %d >\n", __func__, thread_running);
|
||||||
|
if (thread_running) {
|
||||||
|
thread_running = false;
|
||||||
|
OpenThreads::Thread::join();
|
||||||
|
}
|
||||||
|
lt_info("%s running %d <\n", __func__, thread_running);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,9 +150,9 @@ void cVideo::Pig(int, int, int, int, int, int)
|
|||||||
|
|
||||||
void cVideo::getPictureInfo(int &width, int &height, int &rate)
|
void cVideo::getPictureInfo(int &width, int &height, int &rate)
|
||||||
{
|
{
|
||||||
width = 720;
|
width = dec_w;
|
||||||
height = 576;
|
height = dec_h;
|
||||||
rate = 50;
|
rate = dec_r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cVideo::SetSyncMode(AVSYNC_TYPE)
|
void cVideo::SetSyncMode(AVSYNC_TYPE)
|
||||||
@@ -148,3 +163,191 @@ int cVideo::SetStreamType(VIDEO_FORMAT)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cVideo::SWFramebuffer *cVideo::getDecBuf(void)
|
||||||
|
{
|
||||||
|
if (buf_num == 0)
|
||||||
|
return NULL;
|
||||||
|
SWFramebuffer *p = &buffers[buf_out];
|
||||||
|
buf_out++;
|
||||||
|
buf_num--;
|
||||||
|
buf_out %= VDEC_MAXBUFS;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int my_read(void *, uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
int tmp = 0;
|
||||||
|
if (videoDecoder && bufpos < DMX_BUF_SZ - 4096) {
|
||||||
|
while (bufpos < buf_size && ++tmp < 20) { /* retry max 20 times */
|
||||||
|
int ret = videoDemux->Read(dmxbuf + bufpos, DMX_BUF_SZ - bufpos, 20);
|
||||||
|
if (ret > 0)
|
||||||
|
bufpos += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bufpos == 0)
|
||||||
|
return 0;
|
||||||
|
if (bufpos > buf_size) {
|
||||||
|
memcpy(buf, dmxbuf, buf_size);
|
||||||
|
memmove(dmxbuf, dmxbuf + buf_size, bufpos - buf_size);
|
||||||
|
bufpos -= buf_size;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
memcpy(buf, dmxbuf, bufpos);
|
||||||
|
tmp = bufpos;
|
||||||
|
bufpos = 0;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cVideo::run(void)
|
||||||
|
{
|
||||||
|
lt_info("====================== start decoder thread ================================\n");
|
||||||
|
AVCodec *codec;
|
||||||
|
AVCodecContext *c= NULL;
|
||||||
|
AVFormatContext *avfc = NULL;
|
||||||
|
AVInputFormat *inp;
|
||||||
|
AVFrame *frame, *rgbframe;
|
||||||
|
uint8_t *inbuf = (uint8_t *)av_malloc(INBUF_SIZE);
|
||||||
|
AVPacket avpkt;
|
||||||
|
|
||||||
|
time_t warn_r = 0; /* last read error */
|
||||||
|
time_t warn_d = 0; /* last decode error */
|
||||||
|
|
||||||
|
bufpos = 0;
|
||||||
|
buf_num = 0;
|
||||||
|
buf_in = 0;
|
||||||
|
buf_out = 0;
|
||||||
|
|
||||||
|
firstpts = AV_NOPTS_VALUE;
|
||||||
|
framecount = 0;
|
||||||
|
av_init_packet(&avpkt);
|
||||||
|
inp = av_find_input_format("mpegts");
|
||||||
|
AVIOContext *pIOCtx = avio_alloc_context(inbuf, INBUF_SIZE, // internal Buffer and its size
|
||||||
|
0, // bWriteable (1=true,0=false)
|
||||||
|
NULL, // user data; will be passed to our callback functions
|
||||||
|
my_read, // read callback
|
||||||
|
NULL, // write callback
|
||||||
|
NULL); // seek callback
|
||||||
|
avfc = avformat_alloc_context();
|
||||||
|
avfc->pb = pIOCtx;
|
||||||
|
avfc->iformat = inp;
|
||||||
|
avfc->probesize = 188*5;
|
||||||
|
|
||||||
|
thread_running = true;
|
||||||
|
if (avformat_open_input(&avfc, NULL, inp, NULL) < 0) {
|
||||||
|
lt_info("%s: Could not open input\n", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
while (avfc->nb_streams < 1)
|
||||||
|
{
|
||||||
|
lt_info("%s: nb_streams %d, should be 1 => retry\n", __func__, avfc->nb_streams);
|
||||||
|
if (av_read_frame(avfc, &avpkt) < 0)
|
||||||
|
lt_info("%s: av_read_frame < 0\n", __func__);
|
||||||
|
av_free_packet(&avpkt);
|
||||||
|
if (! thread_running)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
lt_info("%s: nb_streams %d\n", __func__, avfc->nb_streams);
|
||||||
|
|
||||||
|
if (avfc->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
|
||||||
|
lt_info("%s: no video codec? 0x%x\n", __func__, avfc->streams[0]->codec->codec_type);
|
||||||
|
|
||||||
|
c = avfc->streams[0]->codec;
|
||||||
|
codec = avcodec_find_decoder(c->codec_id);
|
||||||
|
if (!codec) {
|
||||||
|
lt_info("%s: Codec not found\n", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (avcodec_open2(c, codec, NULL) < 0) {
|
||||||
|
lt_info("%s: Could not open codec\n", __func__);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
frame = avcodec_alloc_frame();
|
||||||
|
rgbframe = avcodec_alloc_frame();
|
||||||
|
if (!frame || !rgbframe) {
|
||||||
|
lt_info("%s: Could not allocate video frame\n", __func__);
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
while (thread_running) {
|
||||||
|
if (av_read_frame(avfc, &avpkt) < 0) {
|
||||||
|
if (warn_r - time(NULL) > 4) {
|
||||||
|
lt_info("%s: av_read_frame < 0\n", __func__);
|
||||||
|
warn_r = time(NULL);
|
||||||
|
}
|
||||||
|
usleep(10000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int got_frame = 0;
|
||||||
|
int len = avcodec_decode_video2(c, frame, &got_frame, &avpkt);
|
||||||
|
if (len < 0) {
|
||||||
|
if (warn_d - time(NULL) > 4) {
|
||||||
|
lt_info("%s: avcodec_decode_video2 %d\n", __func__, len);
|
||||||
|
warn_d = time(NULL);
|
||||||
|
}
|
||||||
|
av_free_packet(&avpkt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (avpkt.size > len)
|
||||||
|
lt_info("%s: WARN: pkt->size %d != len %d\n", __func__, avpkt.size, len);
|
||||||
|
if (got_frame) {
|
||||||
|
unsigned int need = avpicture_get_size(PIX_FMT_RGB32, c->width, c->height);
|
||||||
|
struct SwsContext *convert = sws_getContext(c->width, c->height, c->pix_fmt,
|
||||||
|
c->width, c->height, PIX_FMT_RGB32,
|
||||||
|
SWS_BICUBIC, 0, 0, 0);
|
||||||
|
if (!convert)
|
||||||
|
lt_info("%s: ERROR setting up SWS context\n", __func__);
|
||||||
|
else {
|
||||||
|
SWFramebuffer *f = &buffers[buf_in];
|
||||||
|
if (f->size() < need)
|
||||||
|
f->resize(need);
|
||||||
|
avpicture_fill((AVPicture *)rgbframe, &(*f)[0], PIX_FMT_RGB32,
|
||||||
|
c->width, c->height);
|
||||||
|
sws_scale(convert, frame->data, frame->linesize, 0, c->height,
|
||||||
|
rgbframe->data, rgbframe->linesize);
|
||||||
|
sws_freeContext(convert);
|
||||||
|
// TODO: locking needed!
|
||||||
|
if (dec_w != c->width || dec_h != c->height) {
|
||||||
|
lt_info("%s: pic changed %dx%d -> %dx%d\n", __func__,
|
||||||
|
dec_w, dec_h, c->width, c->height);
|
||||||
|
dec_w = c->width;
|
||||||
|
dec_h = c->height;
|
||||||
|
w_h_changed = true;
|
||||||
|
}
|
||||||
|
f->width(c->width);
|
||||||
|
f->height(c->height);
|
||||||
|
f->pts(av_frame_get_best_effort_timestamp(frame));
|
||||||
|
buf_in++;
|
||||||
|
buf_in %= VDEC_MAXBUFS;
|
||||||
|
buf_num++;
|
||||||
|
if (buf_num > (VDEC_MAXBUFS - 1)) {
|
||||||
|
lt_info("%s: buf_num overflow\n", __func__);
|
||||||
|
buf_out++;
|
||||||
|
buf_out %= VDEC_MAXBUFS;
|
||||||
|
buf_num--;
|
||||||
|
}
|
||||||
|
if (firstpts == AV_NOPTS_VALUE && f->pts() != AV_NOPTS_VALUE)
|
||||||
|
firstpts = f->pts();
|
||||||
|
}
|
||||||
|
dec_r = c->time_base.den/(c->time_base.num * c->ticks_per_frame);
|
||||||
|
framecount++;
|
||||||
|
lt_debug("%s: time_base: %d/%d, ticks: %d rate: %d pts 0x%" PRIx64 "\n", __func__,
|
||||||
|
c->time_base.num, c->time_base.den, c->ticks_per_frame, dec_r,
|
||||||
|
av_frame_get_best_effort_timestamp(frame));
|
||||||
|
}
|
||||||
|
av_free_packet(&avpkt);
|
||||||
|
}
|
||||||
|
out2:
|
||||||
|
avcodec_close(c);
|
||||||
|
avcodec_free_frame(&frame);
|
||||||
|
avcodec_free_frame(&rgbframe);
|
||||||
|
out:
|
||||||
|
avformat_close_input(&avfc);
|
||||||
|
av_free(pIOCtx->buffer);
|
||||||
|
av_free(pIOCtx);
|
||||||
|
/* reset output buffers */
|
||||||
|
bufpos = 0;
|
||||||
|
buf_num = 0;
|
||||||
|
buf_in = 0;
|
||||||
|
buf_out = 0;
|
||||||
|
lt_info("======================== end decoder thread ================================\n");
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
#ifndef _VIDEO_TD_H
|
#ifndef _VIDEO_TD_H
|
||||||
#define _VIDEO_TD_H
|
#define _VIDEO_TD_H
|
||||||
|
|
||||||
|
#include <OpenThreads/Thread>
|
||||||
|
#include <vector>
|
||||||
#include <linux/dvb/video.h>
|
#include <linux/dvb/video.h>
|
||||||
#include "../common/cs_types.h"
|
#include "../common/cs_types.h"
|
||||||
|
|
||||||
@@ -112,9 +114,29 @@ typedef enum
|
|||||||
} VIDEO_CONTROL;
|
} VIDEO_CONTROL;
|
||||||
|
|
||||||
|
|
||||||
class cVideo
|
#define VDEC_MAXBUFS 0x30
|
||||||
|
class cVideo : public OpenThreads::Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/* called from GL thread */
|
||||||
|
class SWFramebuffer : public std::vector<unsigned char>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWFramebuffer() : mWidth(0), mHeight(0) {}
|
||||||
|
void width(int w) { mWidth = w; }
|
||||||
|
void height(int h) { mHeight = h; }
|
||||||
|
void pts(uint64_t p) { mPts = p; }
|
||||||
|
int width() const { return mWidth; }
|
||||||
|
int height() const { return mHeight; }
|
||||||
|
int64_t pts() const { return mPts; }
|
||||||
|
private:
|
||||||
|
int mWidth;
|
||||||
|
int mHeight;
|
||||||
|
int64_t mPts;
|
||||||
|
};
|
||||||
|
int64_t firstpts;
|
||||||
|
uint64_t framecount;
|
||||||
|
int buf_in, buf_out, buf_num;
|
||||||
/* constructor & destructor */
|
/* constructor & destructor */
|
||||||
cVideo(int mode, void *, void *);
|
cVideo(int mode, void *, void *);
|
||||||
~cVideo(void);
|
~cVideo(void);
|
||||||
@@ -163,6 +185,14 @@ class cVideo
|
|||||||
int CloseVBI(void) { return 0; };
|
int CloseVBI(void) { return 0; };
|
||||||
int StartVBI(unsigned short) { return 0; };
|
int StartVBI(unsigned short) { return 0; };
|
||||||
int StopVBI(void) { return 0; };
|
int StopVBI(void) { return 0; };
|
||||||
|
SWFramebuffer *getDecBuf(void);
|
||||||
|
private:
|
||||||
|
void run();
|
||||||
|
SWFramebuffer buffers[VDEC_MAXBUFS];
|
||||||
|
int dec_w, dec_h;
|
||||||
|
int dec_r;
|
||||||
|
bool w_h_changed;
|
||||||
|
bool thread_running;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user