added: bitvlc, playes a video using libvlc and sends it to the bitpanel

This commit is contained in:
Bob van Loosen 2013-02-19 19:39:44 +01:00
parent 700ec3abf2
commit af13595a90
4 changed files with 385 additions and 3 deletions

View file

@ -17,9 +17,91 @@
*/
#include "bitvlc.h"
#include "util/log.h"
#include "util/misc.h"
#include "util/lock.h"
#include <stddef.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
using namespace std;
CBitVlc::CBitVlc(int argc, char *argv[])
{
m_debug = false;
m_debugscale = 2;
m_instance = NULL;
m_player = NULL;
m_media = NULL;
m_port = 1337;
m_address = NULL;
m_width = 120;
m_height = 48;
m_plane = NULL;
m_volume = 0;
m_dither = false;
const char* flags = "p:a:m:d:v:f";
int c;
while ((c = getopt(argc, argv, flags)) != -1)
{
if (c == 'p') //port
{
int port;
if (!StrToInt(string(optarg), port) || port < 0 || port > 65535)
{
LogError("Wrong argument \"%s\" for port", optarg);
exit(1);
}
m_port = port;
}
if (c == 'd') //debug
{
int scale;
if (!StrToInt(string(optarg), scale) || scale < 0 || scale > 65535)
{
LogError("Wrong argument \"%s\" for debug scale", optarg);
exit(1);
}
m_debugscale = scale;
m_debug = true;
}
else if (c == 'a') //address
{
m_address = optarg;
}
else if (c == 'm') //media
{
m_media = optarg;
}
if (c == 'v') //volume
{
int volume;
if (!StrToInt(string(optarg), volume) || volume < 0 || volume > volume)
{
LogError("Wrong argument \"%s\" for volume", optarg);
exit(1);
}
m_volume = volume;
}
else if (c == 'f') //dither
{
m_dither = true;
}
}
if (m_media == NULL)
{
LogError("No media given (use -m path)");
exit(1);
}
if (m_address == NULL)
m_debug = true;
}
CBitVlc::~CBitVlc()
@ -28,13 +110,269 @@ CBitVlc::~CBitVlc()
void CBitVlc::Setup()
{
}
if (m_debug)
m_debugwindow.Enable(m_width, m_height, m_debugscale);
void CBitVlc::Process()
{
m_instance = libvlc_new(0, NULL);
if (m_instance == NULL)
{
LogError("Unable to init VLC");
exit(1);
}
libvlc_media_t* media = libvlc_media_new_path(m_instance, m_media);
m_player = libvlc_media_player_new_from_media(media);
libvlc_media_release(media);
libvlc_video_set_callbacks(m_player, SVLCLock, SVLCUnlock, SVLCDisplay, this);
InitPlane(m_width, m_height);
m_process = false;
m_display = false;
}
void CBitVlc::Cleanup()
{
if (m_player)
libvlc_media_player_release(m_player);
if (m_instance);
libvlc_release(m_instance);
delete[] m_plane;
}
void CBitVlc::Process()
{
libvlc_media_player_play(m_player);
for(;;)
{
if (!m_socket.IsOpen() && m_address)
{
if (m_socket.Open(m_address, m_port, 1000000) != SUCCESS)
{
LogError("Failed to connect: %s", m_socket.GetError().c_str());
m_socket.Close();
}
else
{
Log("Connected");
}
}
CLock lock(m_condition);
while (!m_process)
m_condition.Wait();
m_process = false;
libvlc_audio_set_volume(m_player, m_volume);
unsigned int videowidth = 0;
unsigned int videoheight = 0;
libvlc_video_get_size(m_player, 0, &videowidth, &videoheight);
int neededwidth = Round32((float)videowidth * m_height / videoheight);
int neededheight = Round32((float)videoheight * m_width / videowidth);
if (neededwidth > m_width)
InitPlane(neededwidth, m_height);
else
InitPlane(m_width, neededheight);
int xplanestart = (m_planewidth - m_width) / 2;
int yplanestart = (m_planeheight - m_height) / 2;
int xplaneend = xplanestart + m_width;
int yplaneend = yplanestart + m_height;
int avg = 0;
for (int y = yplanestart; y < yplaneend; y++)
{
uint8_t* planeptr = m_plane + y * m_planewidth * 3 + xplanestart * 3;
uint8_t* end = planeptr + m_width * 3;
while (planeptr != end)
{
avg += *(planeptr++);
avg += *(planeptr++);
planeptr++;
}
}
avg /= m_width * m_height * 2;
CTcpData data;
data.SetData(":00");
uint8_t last;
if (m_dither)
{
for (int y = yplanestart; y < yplaneend; y++)
{
uint8_t* planeptr = m_plane + y * m_planewidth * 3 + xplanestart * 3;
int value;
int quanterror;
for (int x = xplanestart; x < xplaneend; x++)
{
for (int i = 0; i < 2; i++)
{
if (*planeptr > avg)
{
value = 255;
}
else
{
value = 0;
}
quanterror = *planeptr - value;
*planeptr = value;
if (x < xplaneend - 1)
{
*(planeptr + 3) = Clamp(*(planeptr + 3) + quanterror * 7 / 16, 0, 255);
if (y < xplaneend - 1)
*(planeptr + 3 + m_planewidth * 3) = Clamp(*(planeptr + 3 + m_planewidth * 3) + quanterror / 16, 0, 255);
}
if (y < xplaneend - 1)
{
*(planeptr + m_planewidth * 3) = Clamp(*(planeptr + m_planewidth * 3) + quanterror * 5 / 16, 0, 255);
if (x > xplanestart)
*(planeptr - 3 + m_planewidth * 3) = Clamp(*(planeptr - 3 + m_planewidth * 3) + quanterror * 3 / 16, 0, 255);
}
planeptr++;
}
planeptr++;
}
}
avg = 128;
}
{
for (int y = yplanestart; y < yplaneend; y++)
{
uint8_t* planeptr = m_plane + y * m_planewidth * 3 + xplanestart * 3;
uint8_t* end = planeptr + m_width * 3;
uint8_t line[m_width / 4];
uint8_t* lineptr = line;
int pixelcount = 3;
memset(line, 0, sizeof(line));
while (planeptr != end)
{
planeptr++;
if (*(planeptr++) > avg)
*lineptr |= 1 << (pixelcount * 2); //green
if (*(planeptr++) > avg)
*lineptr |= 1 << (pixelcount * 2 + 1); //red
pixelcount--;
if (pixelcount == -1)
{
pixelcount = 3;
lineptr++;
}
}
if (y == yplaneend - 1)
{
//dont add the last byte here, it will be sent later
data.SetData(line, sizeof(line) - 1, true);
last = line[sizeof(line) - 1];
}
else
{
data.SetData(line, sizeof(line), true);
}
}
}
//send everything but the last byte, since the bitpanel is double buffered
//the timing is improved by sending only the last byte when the frame needs to be displayed
lock.Leave();
if (m_socket.IsOpen())
{
if (m_socket.Write(data) != SUCCESS)
{
LogError("%s", m_socket.GetError().c_str());
m_socket.Close();
}
}
m_debugwindow.DisplayFrame(data);
lock.Enter();
while (!m_display)
m_condition.Wait();
m_display = false;
lock.Leave();
uint8_t end[10] = {};
data.SetData(&last, 1);
data.SetData(end, sizeof(end), true);
if (m_socket.IsOpen())
{
if (m_socket.Write(data) != SUCCESS)
{
LogError("%s", m_socket.GetError().c_str());
m_socket.Close();
}
}
m_debugwindow.DisplayFrame(data);
}
libvlc_media_player_stop(m_player);
}
void CBitVlc::InitPlane(int width, int height)
{
if (m_planewidth != width || m_planeheight != height)
{
Log("Setting plane to %ix%i", width, height);
m_planewidth = width;
m_planeheight = height;
delete[] m_plane;
m_plane = new uint8_t[m_planewidth * m_planeheight * 3];
memset(m_plane, 0, m_planewidth * m_planeheight * 3);
//reset the player to update to the new format
libvlc_media_player_stop(m_player);
libvlc_video_set_format(m_player, "RV24", m_planewidth, m_planeheight, m_planewidth * 3);
libvlc_media_player_play(m_player);
}
}
void* CBitVlc::SVLCLock (void *opaque, void **planes)
{
return ((CBitVlc*)opaque)->VLCLock(planes);
}
void CBitVlc::SVLCUnlock (void *opaque, void *picture, void *const *planes)
{
((CBitVlc*)opaque)->VLCUnlock(picture, planes);
}
void CBitVlc::SVLCDisplay(void *opaque, void *picture)
{
((CBitVlc*)opaque)->VLCDisplay(picture);
}
void* CBitVlc::VLCLock (void **planes)
{
m_condition.Lock();
planes[0] = m_plane;
return NULL;
}
void CBitVlc::VLCUnlock (void *picture, void *const *planes)
{
m_process = true;
m_condition.Signal();
m_condition.Unlock();
}
void CBitVlc::VLCDisplay(void *picture)
{
m_condition.Lock();
m_display = true;
m_condition.Signal();
m_condition.Unlock();
}

View file

@ -19,6 +19,11 @@
#ifndef BITVLC_H
#define BITVLC_H
#include <vlc/vlc.h>
#include "util/debugwindow.h"
#include "util/condition.h"
#include "util/tcpsocket.h"
class CBitVlc
{
public:
@ -28,6 +33,39 @@ class CBitVlc
void Setup();
void Process();
void Cleanup();
private:
bool m_debug;
int m_debugscale;
CDebugWindow m_debugwindow;
int m_port;
const char* m_address;
CTcpClientSocket m_socket;
const char* m_media;
libvlc_instance_t* m_instance;
libvlc_media_player_t* m_player;
int m_volume;
int m_width;
int m_height;
bool m_dither;
CCondition m_condition;
uint8_t* m_plane;
int m_planewidth;
int m_planeheight;
bool m_process;
bool m_display;
void InitPlane(int width, int height);
static void* SVLCLock (void *opaque, void **planes);
static void SVLCUnlock (void *opaque, void *picture, void *const *planes);
static void SVLCDisplay(void *opaque, void *picture);
void* VLCLock (void **planes);
void VLCUnlock (void *picture, void *const *planes);
void VLCDisplay(void *picture);
};
#endif //BITVLC_H

View file

@ -17,9 +17,12 @@
*/
#include "bitvlc.h"
#include "util/log.h"
int main (int argc, char *argv[])
{
SetLogFile(".bitvlc", "bitvlc.log");
CBitVlc bitvlc(argc, argv);
bitvlc.Setup();

View file

@ -79,9 +79,12 @@ def build(bld):
bld.program(source='src/bitvlc/main.cpp\
src/bitvlc/bitvlc.cpp\
src/util/condition.cpp\
src/util/debugwindow.cpp\
src/util/log.cpp\
src/util/misc.cpp\
src/util/mutex.cpp\
src/util/thread.cpp\
src/util/timeutils.cpp\
src/util/tcpsocket.cpp',
use=['m', 'rt', 'X11', 'Xrender', 'Xext', 'vlc'],