mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-27 07:23:11 +02:00
raspi: add first try of video decoder implementation
This is very raw and unfinished, it clearly needs some more polishing. But it decodes h264 channels :-)
This commit is contained in:
259
raspi/video.cpp
259
raspi/video.cpp
@@ -23,7 +23,15 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <OpenThreads/Thread>
|
||||||
|
|
||||||
|
#include <bcm_host.h>
|
||||||
|
extern "C" {
|
||||||
|
#include "ilclient.h"
|
||||||
|
}
|
||||||
|
|
||||||
#include "video_lib.h"
|
#include "video_lib.h"
|
||||||
|
#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)
|
||||||
@@ -32,12 +40,40 @@
|
|||||||
cVideo *videoDecoder = NULL;
|
cVideo *videoDecoder = NULL;
|
||||||
int system_rev = 0;
|
int system_rev = 0;
|
||||||
|
|
||||||
|
extern cDemux *videoDemux;
|
||||||
|
static int dec_running = false;
|
||||||
|
|
||||||
|
|
||||||
|
class Dec: public OpenThreads::Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Dec();
|
||||||
|
~Dec();
|
||||||
|
private:
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
Dec::Dec()
|
||||||
|
{
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dec::~Dec()
|
||||||
|
{
|
||||||
|
dec_running = false;
|
||||||
|
join();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Dec *dec = NULL;
|
||||||
|
|
||||||
cVideo::cVideo(int, void *, void *, unsigned int)
|
cVideo::cVideo(int, void *, void *, unsigned int)
|
||||||
{
|
{
|
||||||
lt_debug("%s\n", __func__);
|
lt_debug("%s\n", __func__);
|
||||||
display_aspect = DISPLAY_AR_16_9;
|
display_aspect = DISPLAY_AR_16_9;
|
||||||
display_crop = DISPLAY_AR_MODE_LETTERBOX;
|
display_crop = DISPLAY_AR_MODE_LETTERBOX;
|
||||||
v_format = VIDEO_FORMAT_MPEG2;
|
v_format = VIDEO_FORMAT_MPEG2;
|
||||||
|
bcm_host_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
cVideo::~cVideo(void)
|
cVideo::~cVideo(void)
|
||||||
@@ -64,12 +100,19 @@ int cVideo::setCroppingMode(int)
|
|||||||
int cVideo::Start(void *, unsigned short, unsigned short, void *)
|
int cVideo::Start(void *, unsigned short, unsigned short, void *)
|
||||||
{
|
{
|
||||||
lt_debug("%s running %d >\n", __func__, thread_running);
|
lt_debug("%s running %d >\n", __func__, thread_running);
|
||||||
|
if (!dec) {
|
||||||
|
dec = new Dec();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cVideo::Stop(bool)
|
int cVideo::Stop(bool)
|
||||||
{
|
{
|
||||||
lt_debug("%s running %d >\n", __func__, thread_running);
|
lt_debug("%s running %d >\n", __func__, thread_running);
|
||||||
|
if (dec) {
|
||||||
|
delete dec;
|
||||||
|
dec = NULL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,3 +230,219 @@ void cVideo::SetDemux(cDemux *)
|
|||||||
{
|
{
|
||||||
lt_debug("%s: not implemented yet\n", __func__);
|
lt_debug("%s: not implemented yet\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Dec::run()
|
||||||
|
{
|
||||||
|
hal_set_threadname("hal:vdec");
|
||||||
|
int ret = 0;
|
||||||
|
/* write to file instead of decoding. For testing only. */
|
||||||
|
if (getenv("DEC_OUT")) {
|
||||||
|
lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
FILE *ff = fopen("/tmp/video.pes", "w");
|
||||||
|
unsigned char buf[65536];
|
||||||
|
dec_running = true;
|
||||||
|
while (dec_running)
|
||||||
|
{
|
||||||
|
ret = videoDemux->Read(buf, 65536, 10);
|
||||||
|
if (ret <= 0) {
|
||||||
|
if (!dec_running)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fwrite(buf, 1, ret, ff);
|
||||||
|
}
|
||||||
|
lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
|
||||||
|
/* this code is mostly copied from hello_pi/hello_video example */
|
||||||
|
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
|
||||||
|
OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
|
||||||
|
OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE conc;
|
||||||
|
COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *video_render = NULL, *clock = NULL;
|
||||||
|
COMPONENT_T *list[5];
|
||||||
|
TUNNEL_T tunnel[4];
|
||||||
|
ILCLIENT_T *client;
|
||||||
|
int status = 0;
|
||||||
|
unsigned int data_len = 0;
|
||||||
|
int packet_size = 80<<10; /* 80kB */
|
||||||
|
|
||||||
|
memset(list, 0, sizeof(list));
|
||||||
|
memset(tunnel, 0, sizeof(tunnel));
|
||||||
|
|
||||||
|
if ((client = ilclient_init()) == NULL) {
|
||||||
|
lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OMX_Init() != OMX_ErrorNone) {
|
||||||
|
lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
ilclient_destroy(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// create video_decode
|
||||||
|
if (ilclient_create_component(client, &video_decode, (char *)"video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
|
||||||
|
status = -14;
|
||||||
|
list[0] = video_decode;
|
||||||
|
|
||||||
|
// create video_render
|
||||||
|
if (status == 0 && ilclient_create_component(client, &video_render, (char *)"video_render", ILCLIENT_DISABLE_ALL_PORTS) != 0)
|
||||||
|
status = -14;
|
||||||
|
list[1] = video_render;
|
||||||
|
|
||||||
|
// create clock
|
||||||
|
if (status == 0 && ilclient_create_component(client, &clock, (char *)"clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
|
||||||
|
status = -14;
|
||||||
|
list[2] = clock;
|
||||||
|
|
||||||
|
memset(&cstate, 0, sizeof(cstate));
|
||||||
|
cstate.nSize = sizeof(cstate);
|
||||||
|
cstate.nVersion.nVersion = OMX_VERSION;
|
||||||
|
cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
|
||||||
|
cstate.nWaitMask = 1;
|
||||||
|
if (clock != NULL &&
|
||||||
|
OMX_SetParameter(ILC_GET_HANDLE(clock), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
|
||||||
|
status = -13;
|
||||||
|
|
||||||
|
// create video_scheduler
|
||||||
|
if (status == 0 &&
|
||||||
|
ilclient_create_component(client, &video_scheduler, (char *)"video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0)
|
||||||
|
status = -14;
|
||||||
|
list[3] = video_scheduler;
|
||||||
|
|
||||||
|
set_tunnel(tunnel, video_decode, 131, video_scheduler, 10);
|
||||||
|
set_tunnel(tunnel+1, video_scheduler, 11, video_render, 90);
|
||||||
|
set_tunnel(tunnel+2, clock, 80, video_scheduler, 12);
|
||||||
|
|
||||||
|
// setup clock tunnel first
|
||||||
|
if (status == 0 && ilclient_setup_tunnel(tunnel+2, 0, 0) != 0)
|
||||||
|
status = -15;
|
||||||
|
else
|
||||||
|
ilclient_change_component_state(clock, OMX_StateExecuting);
|
||||||
|
|
||||||
|
if (status == 0)
|
||||||
|
ilclient_change_component_state(video_decode, OMX_StateIdle);
|
||||||
|
|
||||||
|
memset(&conc, 0, sizeof(conc));
|
||||||
|
conc.nSize = sizeof(conc);
|
||||||
|
conc.nVersion.nVersion = OMX_VERSION;
|
||||||
|
conc.bStartWithValidFrame = OMX_FALSE;
|
||||||
|
if (status == 0 &&
|
||||||
|
OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamBrcmVideoDecodeErrorConcealment, &conc) != OMX_ErrorNone)
|
||||||
|
status = -16;
|
||||||
|
|
||||||
|
memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
|
||||||
|
format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
|
||||||
|
format.nVersion.nVersion = OMX_VERSION;
|
||||||
|
format.nPortIndex = 130;
|
||||||
|
format.eCompressionFormat = OMX_VIDEO_CodingAVC;
|
||||||
|
// format.xFramerate = 50 * (1 << 16);
|
||||||
|
|
||||||
|
lt_info_c("Dec::run %d status %d\n", __LINE__, status);
|
||||||
|
if (status == 0 &&
|
||||||
|
OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
|
||||||
|
ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0)
|
||||||
|
{
|
||||||
|
OMX_BUFFERHEADERTYPE *buf;
|
||||||
|
int port_settings_changed = 0;
|
||||||
|
int first_packet = 1;
|
||||||
|
dec_running = true;
|
||||||
|
|
||||||
|
ilclient_change_component_state(video_decode, OMX_StateExecuting);
|
||||||
|
|
||||||
|
lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
while ((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
|
||||||
|
{
|
||||||
|
// feed data and wait until we get port settings changed
|
||||||
|
unsigned char *dest = buf->pBuffer;
|
||||||
|
again:
|
||||||
|
//lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
ret = videoDemux->Read(dest, packet_size-data_len, 10);
|
||||||
|
if (ret <= 0) {
|
||||||
|
if (!dec_running)
|
||||||
|
break;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_len += ret;
|
||||||
|
//lt_info_c("Dec::run %d data_len %d\n", __LINE__, data_len);
|
||||||
|
|
||||||
|
if (port_settings_changed == 0 &&
|
||||||
|
((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
|
||||||
|
(data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
|
||||||
|
ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
|
||||||
|
{
|
||||||
|
port_settings_changed = 1;
|
||||||
|
|
||||||
|
if (ilclient_setup_tunnel(tunnel, 0, 0) != 0) {
|
||||||
|
status = -7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ilclient_change_component_state(video_scheduler, OMX_StateExecuting);
|
||||||
|
|
||||||
|
// now setup tunnel to video_render
|
||||||
|
if (ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0) {
|
||||||
|
status = -12;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ilclient_change_component_state(video_render, OMX_StateExecuting);
|
||||||
|
}
|
||||||
|
if (!data_len)
|
||||||
|
break;
|
||||||
|
if (! dec_running)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buf->nFilledLen = data_len;
|
||||||
|
data_len = 0;
|
||||||
|
|
||||||
|
buf->nOffset = 0;
|
||||||
|
if (first_packet) {
|
||||||
|
buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
|
||||||
|
first_packet = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
|
||||||
|
|
||||||
|
if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone) {
|
||||||
|
status = -6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lt_info_c("Dec::run %d\n", __LINE__);
|
||||||
|
|
||||||
|
buf->nFilledLen = 0;
|
||||||
|
buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
|
||||||
|
|
||||||
|
if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
|
||||||
|
status = -20;
|
||||||
|
|
||||||
|
// wait for EOS from render
|
||||||
|
ilclient_wait_for_event(video_render, OMX_EventBufferFlag, 90, 0, OMX_BUFFERFLAG_EOS, 0,
|
||||||
|
ILCLIENT_BUFFER_FLAG_EOS, 10000);
|
||||||
|
|
||||||
|
// need to flush the renderer to allow video_decode to disable its input port
|
||||||
|
ilclient_flush_tunnels(tunnel, 0);
|
||||||
|
|
||||||
|
ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ilclient_disable_tunnel(tunnel);
|
||||||
|
ilclient_disable_tunnel(tunnel+1);
|
||||||
|
ilclient_disable_tunnel(tunnel+2);
|
||||||
|
ilclient_teardown_tunnels(tunnel);
|
||||||
|
|
||||||
|
ilclient_state_transition(list, OMX_StateIdle);
|
||||||
|
ilclient_state_transition(list, OMX_StateLoaded);
|
||||||
|
|
||||||
|
ilclient_cleanup_components(list);
|
||||||
|
|
||||||
|
OMX_Deinit();
|
||||||
|
|
||||||
|
ilclient_destroy(client);
|
||||||
|
lt_info_c("Dec::run %d ends\n", __LINE__);
|
||||||
|
// return status;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user