Skip to content

Instantly share code, notes, and snippets.

@croepha
Created January 2, 2017 09:44
Show Gist options
  • Save croepha/4f6fedff15a77a588ff9337bab25b602 to your computer and use it in GitHub Desktop.
Save croepha/4f6fedff15a77a588ff9337bab25b602 to your computer and use it in GitHub Desktop.
Lib vlc testing
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mutex.h>
#include <epoxy/gl.h>
#include <epoxy/glx.h>
#include <vlc/vlc.h>
#define WIDTH 640
#define HEIGHT 480
// #define VIDEOWIDTH 320
// #define VIDEOHEIGHT 240
struct ctx
{
SDL_mutex *mutex;
};
void* tex_mem;
typedef unsigned int u32;
u32 VIDEOHEIGHT;
u32 VIDEOWIDTH;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wswitch"
void _check_gl_error(const char *file, int line) {
GLenum err = glGetError();
while(err!=GL_NO_ERROR) {
const char *error;
switch(err) {
case GL_INVALID_OPERATION: error="INVALID_OPERATION"; break;
case GL_INVALID_ENUM: error="INVALID_ENUM"; break;
case GL_INVALID_VALUE: error="INVALID_VALUE"; break;
case GL_OUT_OF_MEMORY: error="OUT_OF_MEMORY"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: error="INVALID_FRAMEBUFFER_OPERATION"; break;
}
printf("%s, %s:%d \n", error, file, line);
err=glGetError();
}
}
#pragma clang diagnostic pop
#define GL_CHECK() _check_gl_error(__FILE__,__LINE__)
unsigned char c;
static void *lock(void *data, void **p_pixels)
{
struct ctx *ctx = (struct ctx *)data;
SDL_LockMutex(ctx->mutex);
// printf("lock\n");
// *p_pixels = tex_mem;
// for (int x=0; x<100; x++) {
// for (int y=0; y<100; y++) {
// auto p = ((uint8_t*)tex_mem) + (y + 10)*VIDEOWIDTH*4 + (x + 10)*4;
// p[0] = c++;
// // p[1] = 255;
// // p[2] = 0;
// p[3] = 255;
// }
// }
return NULL; /* picture identifier, not needed here */
}
static void unlock(void *data, void *id, void *const *p_pixels)
{
struct ctx *ctx = (struct ctx *)data;
SDL_UnlockMutex(ctx->mutex);
assert(id == NULL); /* picture identifier, not needed here */
}
static void display(void *data, void *id)
{
/* VLC wants to display the video */
(void) data;
assert(id == NULL);
}
void _event(const libvlc_event_t *event, void *data) {
// P_ERR;
switch (event->type) {
#define _e(event) case event: printf("event->type:%s ",#event); break
_e(libvlc_MediaSubItemAdded);
_e(libvlc_MediaDurationChanged);
_e(libvlc_MediaParsedChanged);
_e(libvlc_MediaFreed);
_e(libvlc_MediaStateChanged);
_e(libvlc_MediaSubItemTreeAdded);
_e(libvlc_MediaPlayerMediaChanged);
_e(libvlc_MediaPlayerNothingSpecial);
_e(libvlc_MediaPlayerOpening);
_e(libvlc_MediaPlayerBuffering);
_e(libvlc_MediaPlayerPlaying);
_e(libvlc_MediaPlayerPaused);
_e(libvlc_MediaPlayerStopped);
_e(libvlc_MediaPlayerForward);
_e(libvlc_MediaPlayerBackward);
_e(libvlc_MediaPlayerEndReached);
_e(libvlc_MediaPlayerEncounteredError);
_e(libvlc_MediaPlayerTimeChanged);
_e(libvlc_MediaPlayerPositionChanged);
_e(libvlc_MediaPlayerSeekableChanged);
_e(libvlc_MediaPlayerPausableChanged);
_e(libvlc_MediaPlayerTitleChanged);
_e(libvlc_MediaPlayerSnapshotTaken);
_e(libvlc_MediaPlayerLengthChanged);
_e(libvlc_MediaPlayerVout);
_e(libvlc_MediaPlayerScrambledChanged);
_e(libvlc_MediaPlayerCorked);
_e(libvlc_MediaPlayerUncorked);
_e(libvlc_MediaPlayerMuted);
_e(libvlc_MediaPlayerUnmuted);
_e(libvlc_MediaPlayerAudioVolume);
#undef _e
}
printf("got to %s\n", __func__);
// auto ctx = (Context*)data;
// u32 w, h;
// libvlc_video_get_size(ctx->mp, 0, &w, &h);
// if (w != ctx->width || h != ctx->height) {
// ctx->width = w;
// ctx->height = h;
// printf("got size3: %d, %d \n", ctx->width, ctx->height);
// }
// (void)ctx;
libvlc_media_t* m = (libvlc_media_t*)data;
libvlc_media_track_info_t * tracks = NULL;
libvlc_media_get_tracks_info(m, &tracks);
if( tracks )
{
int width = tracks->u.video.i_width;
int height = tracks->u.video.i_height;
printf( "%d x %d \n", width, height);
free(tracks);
}
else
{
printf("tracks is NULL\n");
}
}
#include <unistd.h>
u32 setup(void **opaque, char *chroma, u32 *width, u32 *height, u32 *pitches, u32 *lines) {
struct ctx *ctx = (struct ctx *)*opaque;
SDL_LockMutex(ctx->mutex);
printf("got to %s chroma:%s width:%u height:%u, pitches:%u,%u,%u,%u lines:%u,%u,%u,%u \n",
__func__, chroma, *width, *height,
*pitches, *(pitches +1), *(pitches +2), *(pitches +3),
*lines, *(lines +1), *(lines +2), *(lines +3)
);
VIDEOWIDTH = *width;
VIDEOHEIGHT = *height;
memcpy(chroma, "RV32", 4);
tex_mem = malloc(*width * *height * 4);
memset(tex_mem, 0xFF, VIDEOHEIGHT * VIDEOHEIGHT * 4);
SDL_UnlockMutex(ctx->mutex);
return 1;
}
void cleanup(void *opaque) {
printf("got to %s\n", __func__);
}
int main(int argc, char *argv[])
{
libvlc_instance_t *libvlc;
libvlc_media_t *m;
libvlc_media_player_t *mp;
char const *vlc_argv[] =
{
"--quiet",
"--ignore-config",
"--no-video-title",
"--no-xlib", /* tell VLC to not use Xlib */
};
int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
SDL_Surface *screen;
SDL_Event event;
int done = 0, action = 0, pause = 0, n = 0;
struct ctx ctx;
if(argc < 2)
{
printf("Usage: %s <filename>\n", argv[0]);
return EXIT_FAILURE;
}
/*
* Initialise libSDL
*/
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTTHREAD) == -1)
{
printf("cannot initialize SDL\n");
return EXIT_FAILURE;
}
ctx.mutex = SDL_CreateMutex();
int options = SDL_ANYFORMAT | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_OPENGL;
screen = SDL_SetVideoMode(WIDTH, HEIGHT, 0, options);
if(!screen)
{
printf("cannot set video mode\n");
return EXIT_FAILURE;
}
/*
* Initialise libVLC
*/
libvlc = libvlc_new(vlc_argc, vlc_argv);
// m = libvlc_media_new_path(libvlc, argv[1]);
m = libvlc_media_new_location(libvlc, "http://www.streambox.fr/playlists/x36xhzz/x36xhzz.m3u8");
auto media_event_manager = libvlc_media_event_manager(m);
#define _e(event) assert(!libvlc_event_attach(media_event_manager, event, _event, m))
_e(libvlc_MediaSubItemAdded);
_e(libvlc_MediaDurationChanged);
_e(libvlc_MediaParsedChanged);
_e(libvlc_MediaFreed);
_e(libvlc_MediaStateChanged);
_e(libvlc_MediaSubItemTreeAdded);
#undef _e
libvlc_media_parse(m);
libvlc_media_track_info_t * tracks = NULL;
libvlc_media_get_tracks_info(m, &tracks);
if( tracks )
{
int width = tracks->u.video.i_width;
int height = tracks->u.video.i_height;
printf( "%d x %d \n", width, height);
free(tracks);
}
else
{
printf("tracks is NULL\n");
}
// libvlc_media_track_info_t * tracks = NULL;
// libvlc_media_get_tracks_info(m, &tracks);
// if( tracks )
// {
// int width = tracks->u.video.i_width;
// int height = tracks->u.video.i_height;
// printf( "%d x %d \n", width, height);
// free(tracks);
// }
// else
// {
// printf("tracks is NULL\n");assert(false);
// }
mp = libvlc_media_player_new_from_media(m);
libvlc_media_release(m);
libvlc_video_set_callbacks(mp, lock, unlock, display, &ctx);
libvlc_video_set_format_callbacks(mp, setup, cleanup);
// // libvlc_video_get_size(ctx->mp, 0, &ctx->width, &ctx->height);
// unsigned int VIDEOWIDTH = 0;
// unsigned int VIDEOHEIGHT = 0;
// VIDEOWIDTH = 1280; VIDEOHEIGHT = 720;
// unsigned int VIDEOWIDTH_ = 0;
// unsigned int VIDEOHEIGHT_ = 0;
// // while(!VIDEOWIDTH_ || !VIDEOHEIGHT_) {
// // libvlc_video_get_size(mp, 0, &VIDEOWIDTH_, &VIDEOHEIGHT_);
// // }
// // printf("got size: %u, %u\n", VIDEOHEIGHT, VIDEOWIDTH);
// // printf("got size_: %u, %u\n", VIDEOHEIGHT_, VIDEOWIDTH_);
// printf("Sleeping\n"); sleep(10);
// printf("Done Sleeping\n");
// libvlc_video_set_format(mp, "RV32", VIDEOWIDTH, VIDEOHEIGHT, VIDEOWIDTH*4);
libvlc_media_player_play(mp);
libvlc_media_player_set_pause(mp, 1);
libvlc_media_player_set_pause(mp, 0);
/*
* Main loop
*/
glEnable(GL_TEXTURE_2D);
glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLuint image;
printf("SLEEPING\n");
sleep(5);
printf("DONE SLEEPING\n");
glGenTextures(1, &image);
glBindTexture(GL_TEXTURE_2D, image);
SDL_LockMutex(ctx.mutex);
//SDL_BlitSurface(ctx.surf, NULL, screen, NULL);
//gluBuild2DMipmaps(GL_TEXTURE_2D, 4, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (Uint8 *) raw);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
{
printf(" init VIDEOWIDTH:%d VIDEOHEIGHT:%d\n ", VIDEOWIDTH, VIDEOHEIGHT);
}
GL_CHECK();
// for (int x=0; x<100; x++) {
// for (int y=0; y<100; y++) {
// auto p = ((uint8_t*)tex_mem) + y*VIDEOWIDTH*4 + x*4;
// p[0] = 128;
// p[1] = 255;
// p[2] = 0;
// p[3] = 255;
// }
// }
//glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, VIDEOWIDTH, VIDEOHEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE,(Uint8 *) tex_mem);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, VIDEOWIDTH, VIDEOHEIGHT);
GL_CHECK();
SDL_UnlockMutex(ctx.mutex);
while(!done)
{
action = 0;
/* Keys: enter (fullscreen), space (pause), escape (quit) */
while( SDL_PollEvent( &event ) )
{
switch(event.type)
{
case SDL_QUIT:
done = 1;
break;
case SDL_KEYDOWN:
action = event.key.keysym.sym;
break;
}
}
switch(action)
{
case SDLK_ESCAPE:
done = 1;
break;
case SDLK_RETURN:
options ^= SDL_FULLSCREEN;
screen = SDL_SetVideoMode(WIDTH, HEIGHT, 0, options);
break;
case ' ':
pause = !pause;
break;
}
if(!pause)
n++;
glClear(GL_COLOR_BUFFER_BIT);
/* Blitting the surface does not prevent it from being locked and
* written to by another thread, so we use this additional mutex. */
SDL_LockMutex(ctx.mutex);
//SDL_BlitSurface(ctx.surf, NULL, screen, NULL);
//gluBuild2DMipmaps(GL_TEXTURE_2D, 4, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (Uint8 *) raw);
// glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, VIDEOWIDTH, VIDEOHEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE,(Uint8 *) tex_mem);
GL_CHECK();
if(tex_mem) {
// printf("VIDEOWIDTH:%d VIDEOHEIGHT:%d\n ", VIDEOWIDTH, VIDEOHEIGHT);
// for (int x=0; x<100; x++) {
// for (int y=0; y<100; y++) {
// auto p = ((uint8_t*)tex_mem) + y*VIDEOWIDTH*4 + x*4;
// p[0] = 128;
// p[1] = 255;
// p[2] = 0;
// p[3] = 255;
// }
// }
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEOWIDTH, VIDEOHEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, tex_mem);
}
GL_CHECK();
SDL_UnlockMutex(ctx.mutex);
//SDL_Flip(screen);
// glDisable(GL_TEXTURE_2D);
// glBegin(GL_QUADS);
// glColor3f(1,1,1);
// glVertex2f(0, 0.9);
// glVertex2f(0.9, 0.9);
// glVertex2f(0.9, 0);
// glVertex2f(0, 0);
// glEnd();
// glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2d(0, 1);
glVertex2f(0, 0.9);
glTexCoord2d(1, 1);
glVertex2f(0.9, 0.9);
glTexCoord2d(1, 0);
glVertex2f(0.9, 0);
glTexCoord2d(0, 0);
glVertex2f(0, 0);
glEnd();
glFlush();
SDL_GL_SwapBuffers();
//SDL_Delay(5);
//SDL_BlitSurface(empty, NULL, screen, NULL);
//use SDL timers to determine playback
//printf("%i %i\n",libvlc_media_player_get_length(mp)-1000,libvlc_media_player_get_time(mp));
if(libvlc_media_player_get_length(mp)-1000 == libvlc_media_player_get_time(mp)){
done = 1;
}
}
glDeleteTextures(1, &image);
/*
* Stop stream and clean up libVLC
*/
libvlc_media_player_stop(mp);
libvlc_media_player_release(mp);
libvlc_release(libvlc);
/*
* Close window and clean up libSDL
*/
SDL_DestroyMutex(ctx.mutex);
free(tex_mem);
//SDL_FreeSurface(empty);
SDL_Quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment