Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- libvlc with libsdl, tested on windows 7 and debian 8
- // note : libvlc want pitches and lines to be multiple of 32
- // : other libs are demanding somewhat the same things...(can even have an x,y offset)
- // note : libsdl needs continuous data for the update-texture API
- // it also has an update-texture for y,u,v planes with pitches
- // but both do not accept an x or y offset
- // it also has the limitation that NV12 and NV21 are not supported for the per y,u,v update-texture
- //
- // so, frames are/could be aligned to accommodate hardware and or codecs that assume things.
- //
- // To counter the above limitations i made the streaming texture using the new aligned(frame) size
- // , and specified a src-rect for the video when using render-copy.
- */
- #include <stdio.h>
- #include <stdint.h>
- #include <stdlib.h>
- #if defined(_WIN32)
- #if defined(_MSC_VER) && !defined(__cplusplus) // using visual studio and c ?
- #define inline __inline
- #if _MSC_VER <= 1700 // for VS 2012 and less
- // create a 'stdbool.h' file with this in it :
- // #pragma once
- // typedef int bool;
- // #define false 0
- // #define true 1
- // and move it to a place where the compiler/libvlc can find it
- #endif
- #endif
- #include "SDL.h"
- #include <windows.h>
- #else
- #include "SDL2/SDL.h"
- #endif
- #include "vlc/vlc.h"
- #define WIDTH 640
- #define HEIGHT 360
- #define ALIGN32(type,x) ((((type)x) + (type)31) & ~(type)31)
- // all we use
- typedef struct vid_context
- {
- libvlc_instance_t *vlc_inst; // 'main' libvlc instance
- libvlc_media_player_t *vlc_mp; // media player that will hold our media object created from 'file/url'
- //
- SDL_Window *sdl_win;
- SDL_Renderer *sdl_ren; // a place to draw
- SDL_RendererInfo sdl_ren_info; // contains the formats natively supported by current renderer
- SDL_Texture *sdl_text; // a streaming texture, to upload pixel data each frame
- SDL_Rect sdl_aspect_ratio;
- SDL_cond *sdl_gui_cond; // a condition to wake up libsdl's GUI thread (no SDL_Delay(x) in poll loop)
- SDL_mutex *sdl_gui_cond_lock; // a condition needs a lock
- SDL_bool sdl_gui_conditioned; // condition fired up?
- //
- SDL_mutex *vid_lock; // pixel data access is unique
- Uint32 vid_sdl_format; // format we requested from libvlc for streaming texture(may not be the same as source)
- void* vid_data; // allocated memory for libvlc
- void* vid_planes[3]; // pointers to the memory planes
- int vid_pitch[3];
- int w_video; // reported width video
- int h_video; // reported height video
- int w_frame; // aligned width video
- int h_frame; // aligned height video
- SDL_Rect box; // the rectangle in the frame that contains the video pixels
- Uint32 vid_sdl_event; // a registered libsdl user event
- } vid_context;
- void *vlc_lock_cb(void *opaque, void **planes)
- {
- vid_context *c = (vid_context *)opaque;
- SDL_LockMutex(c->vid_lock);
- planes[0] = c->vid_planes[0], planes[1] = c->vid_planes[1], planes[2] = c->vid_planes[2];
- return NULL; // Picture identifier, not used here.
- }
- void vlc_unlock_cb(void *opaque, void *id, void *const *planes)
- {
- vid_context *c = (vid_context *)opaque;
- SDL_UnlockMutex(c->vid_lock);
- }
- void vlc_display_cb(void *opaque, void *id)
- {
- vid_context *c = (vid_context *)opaque;
- // inform SDL's thread that the frame needs to be displayed
- SDL_Event ev;
- ev.type = c->vid_sdl_event;
- ev.user.code = 2;
- SDL_PushEvent(&ev);
- // wake-up SDL's thread
- SDL_LockMutex(c->sdl_gui_cond_lock);
- c->sdl_gui_conditioned = SDL_TRUE;
- SDL_CondSignal(c->sdl_gui_cond);
- SDL_UnlockMutex(c->sdl_gui_cond_lock);
- }
- // should do: create a _vlc_to_sdl_format(), _sdl_to_vlc_chroma() and a _sdl_get_closest_supported(src_format) function
- unsigned vlc_format_cb(void **opaque, char *chroma, unsigned *width, unsigned *height
- , unsigned *pitches, unsigned *lines)
- {
- vid_context *c = (vid_context *)*opaque;
- Uint32 i;
- SDL_Event ev;
- bool vlc_is_iyuv = (SDL_memcmp(chroma, "I420", 4) == 0)
- , vlc_is_yv12 = (SDL_memcmp(chroma, "YV12", 4) == 0);
- printf("[-] format : in chroma = %s, size = %u/%u\n", chroma, *width, *height);
- // no size or an unexpected callback
- if ((*width) == 0 || (*height) == 0 || c->vid_data != NULL)
- return 0;
- // check if SDL's current renderer supports I420(IYUV) or YV12
- for ( i=0; c->vid_sdl_format == SDL_PIXELFORMAT_UNKNOWN && i < c->sdl_ren_info.num_texture_formats; i++) {
- if (c->sdl_ren_info.texture_formats[i] == SDL_PIXELFORMAT_IYUV && vlc_is_iyuv)
- c->vid_sdl_format = SDL_PIXELFORMAT_IYUV;
- else if (c->sdl_ren_info.texture_formats[i] == SDL_PIXELFORMAT_YV12 && vlc_is_yv12)
- c->vid_sdl_format = SDL_PIXELFORMAT_YV12;
- }
- // else default to rgb
- if (c->vid_sdl_format == SDL_PIXELFORMAT_UNKNOWN) {
- if (SDL_memcmp(chroma, "BGRA", 4) != 0)
- SDL_memcpy(chroma, "RV32", 4); // "RV32"(24 pushed into 32),"BGRA"
- c->vid_sdl_format = SDL_PIXELFORMAT_BGRA32;
- }
- // set pitches/lines, allocate and copy settings
- if (c->vid_sdl_format == SDL_PIXELFORMAT_BGRA32) {
- pitches[0] = ALIGN32(unsigned, (*width) * 4);
- pitches[1] = pitches[2] = 0;
- lines[0] = ALIGN32(unsigned, (*height));
- lines[1] = lines[2] = 0;
- c->w_frame = pitches[0] / 4;
- c->h_frame = lines[0];
- c->vid_data = SDL_malloc((pitches[0] * lines[0]) + 31);
- c->vid_planes[0] = (void*)ALIGN32(uintptr_t, c->vid_data);
- c->vid_planes[1] = c->vid_planes[2] = NULL;
- } else { // I420(IYUV) and YV12
- pitches[0] = ALIGN32(unsigned, (*width));
- pitches[1] = pitches[2] = pitches[0] / 2;
- lines[0] = ALIGN32(unsigned, (*height));
- lines[1] = lines[2] = lines[0] / 2;
- c->w_frame = pitches[0];
- c->h_frame = lines[0];
- c->vid_data = SDL_malloc((pitches[0] * lines[0]) + (pitches[1] * lines[1]) + (pitches[2] * lines[2]) + 31);
- c->vid_planes[0] = (void*)ALIGN32(uintptr_t, c->vid_data);
- c->vid_planes[1] = (void*)((uintptr_t)c->vid_planes[0] + (pitches[0] * lines[0]));
- c->vid_planes[2] = (void*)((uintptr_t)c->vid_planes[1] + (pitches[1] * lines[1]));
- }
- c->vid_pitch[0] = (int)pitches[0], c->vid_pitch[1] = c->vid_pitch[2] = (int)pitches[1];
- c->box.w = c->w_video = (int)*width;
- c->box.h = c->h_video = (int)*height;
- c->box.x = c->box.y = 0;
- // inform SDL's thread the video and frame size are known
- ev.type = c->vid_sdl_event;
- ev.user.code = 1;
- SDL_PushEvent(&ev);
- printf("[-] format : out chroma = %s, size = %d/%d, frame = %d/%d, format = %s\n"
- , chroma, c->w_video, c->h_video, c->w_frame, c->h_frame, SDL_GetPixelFormatName(c->vid_sdl_format));
- return (c->vid_data != NULL);
- }
- void sdl_renderer_change(vid_context *vid)
- {
- if (vid->sdl_text != NULL) SDL_DestroyTexture(vid->sdl_text);
- if (vid->sdl_ren != NULL) SDL_DestroyRenderer(vid->sdl_ren);
- vid->sdl_ren = SDL_CreateRenderer(vid->sdl_win, -1, 0);
- SDL_GetRendererInfo(vid->sdl_ren, &vid->sdl_ren_info);
- if (vid->sdl_text != NULL)
- vid->sdl_text = SDL_CreateTexture( vid->sdl_ren, vid->vid_sdl_format, SDL_TEXTUREACCESS_STREAMING, vid->w_frame, vid->h_frame);
- }
- void sdl_draw_frame(vid_context *vid)
- {
- SDL_SetRenderDrawBlendMode(vid->sdl_ren, SDL_BLENDMODE_NONE);
- SDL_SetRenderDrawColor(vid->sdl_ren, 0, 0, 0, SDL_ALPHA_OPAQUE);
- SDL_RenderClear(vid->sdl_ren);
- if (vid->sdl_text != NULL) {
- SDL_LockMutex(vid->vid_lock);
- SDL_UpdateTexture(vid->sdl_text, NULL, vid->vid_planes[0], vid->vid_pitch[0]);
- SDL_UnlockMutex(vid->vid_lock);
- SDL_RenderCopy(vid->sdl_ren, vid->sdl_text, &vid->box, &vid->sdl_aspect_ratio);
- }
- // draw something on top of the video
- {
- SDL_Rect rc = { 4, 4, 32, 32};
- SDL_SetRenderDrawBlendMode(vid->sdl_ren, SDL_BLENDMODE_BLEND);
- SDL_SetRenderDrawColor(vid->sdl_ren, 22, 80, 43, 127);
- SDL_RenderFillRect(vid->sdl_ren, &rc);
- SDL_SetRenderDrawColor(vid->sdl_ren, 70, 255, 0, 63);
- SDL_RenderDrawRect(vid->sdl_ren, &rc);
- rc.x+=4, rc.y+=4, rc.w-=8, rc.h-=8;
- SDL_RenderDrawRect(vid->sdl_ren, &rc);
- rc.x+=4, rc.y+=4, rc.w-=8, rc.h-=8;
- SDL_RenderDrawRect(vid->sdl_ren, &rc);
- }
- SDL_RenderPresent(vid->sdl_ren);
- }
- int init_libs(vid_context *vid, const char *url, int win_width, int win_height)
- {
- libvlc_media_t *vlc_m;
- char const *vlc_argv[] = {
- "--ignore-config",
- //"--verbose=2"
- };
- int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
- Uint32 i;
- if (SDL_Init(SDL_INIT_VIDEO) < 0) {
- printf("Could not initialize SDL: %s.\n", SDL_GetError());
- return EXIT_FAILURE;
- }
- SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
- SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); // direct3d, opengl, software
- vid->sdl_win = SDL_CreateWindow("ArgvPlayer", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED
- , win_width, win_height, SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
- if (vid->sdl_win == NULL) {
- printf("Could not create window: %s\n", SDL_GetError());
- return EXIT_FAILURE;
- }
- vid->sdl_ren = SDL_CreateRenderer(vid->sdl_win, -1, 0);
- if (vid->sdl_ren == NULL) {
- printf("Could not create renderer: %s\n", SDL_GetError());
- return EXIT_FAILURE;
- }
- SDL_GetRendererInfo(vid->sdl_ren, &vid->sdl_ren_info);
- printf("[-] renderer name = %s, num_texture_formats = %u\n"
- , vid->sdl_ren_info.name, vid->sdl_ren_info.num_texture_formats);
- for ( i=0; i < vid->sdl_ren_info.num_texture_formats; i++)
- printf("[-] %u = %s\n", i+1, SDL_GetPixelFormatName(vid->sdl_ren_info.texture_formats[i]));
- vid->sdl_text = NULL;
- vid->vid_data = NULL;
- vid->vid_sdl_format = SDL_PIXELFORMAT_UNKNOWN;
- vid->vid_sdl_event = SDL_RegisterEvents(1);
- vid->vid_lock = SDL_CreateMutex();
- vid->sdl_gui_cond_lock = SDL_CreateMutex();
- if (vid->vid_lock == NULL || vid->sdl_gui_cond_lock == NULL) {
- printf("Could not create mutex: %s\n", SDL_GetError());
- return EXIT_FAILURE;
- }
- vid->sdl_gui_cond = SDL_CreateCond();
- if (vid->sdl_gui_cond == NULL) {
- printf("Could not create condition: %s\n", SDL_GetError());
- return EXIT_FAILURE;
- }
- vid->sdl_gui_conditioned = SDL_FALSE;
- vid->vlc_inst = libvlc_new(vlc_argc, vlc_argv);
- if (vid->vlc_inst == NULL) {
- printf("Could not initialize LibVLC: %s.\n", libvlc_errmsg());
- return EXIT_FAILURE;
- }
- if (SDL_strstr(url,"://") != NULL)
- vlc_m = libvlc_media_new_location(vid->vlc_inst, url);
- else
- vlc_m = libvlc_media_new_path(vid->vlc_inst, url);
- if (vlc_m == NULL) {
- printf("Could not create new media for LibVLC: %s.\n", libvlc_errmsg());
- return EXIT_FAILURE;
- }
- libvlc_media_parse(vlc_m);
- vid->vlc_mp = libvlc_media_player_new_from_media(vlc_m);
- if (vid->vlc_mp == NULL) {
- printf("Could not create new media player for LibVLC: %s.\n", libvlc_errmsg());
- return EXIT_FAILURE;
- }
- libvlc_media_release(vlc_m); // media_player holds a reference now
- libvlc_video_set_callbacks(vid->vlc_mp, vlc_lock_cb, vlc_unlock_cb, vlc_display_cb, vid);
- libvlc_video_set_format_callbacks(vid->vlc_mp, vlc_format_cb, NULL);
- libvlc_audio_set_volume(vid->vlc_mp, 25);
- libvlc_media_player_play(vid->vlc_mp);
- return 0;
- }
- int main(int argc, char *argv[])
- {
- vid_context vid_ctx;
- SDL_Event ev;
- Uint32 fullscreen = 0, done = 0, do_draw = 0;
- SDL_Rect view_tmp;
- float r;
- #if defined(_WIN32)
- AllocConsole();
- freopen("CONOUT$", "w", stdout);
- #endif
- if (argc < 2) {
- printf("Usage: %s <filename/url>\n", argv[0]);
- SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Input", "Give me a <filename/url>", NULL);
- return EXIT_FAILURE;
- }
- if (init_libs( &vid_ctx, argv[1] , WIDTH, HEIGHT) != 0) {
- SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Oopsie Doopsie", "Don't shoot the messenger", NULL);
- return EXIT_FAILURE;
- }
- // Main loop.
- while (!done)
- {
- while (SDL_PollEvent( &ev )) {
- switch (ev.type) {
- case SDL_QUIT: done = 1; break;
- case SDL_KEYDOWN:
- switch(ev.key.keysym.sym) {
- case SDLK_ESCAPE: done = 1; break;
- case SDLK_SPACE:
- if (libvlc_media_player_can_pause(vid_ctx.vlc_mp))
- libvlc_media_player_pause(vid_ctx.vlc_mp);
- break;
- default: break;
- }
- break;
- case SDL_MOUSEWHEEL:
- libvlc_audio_set_volume(vid_ctx.vlc_mp, libvlc_audio_get_volume(vid_ctx.vlc_mp) + (ev.wheel.y * 4));
- break;
- case SDL_MOUSEBUTTONUP:
- if (ev.button.clicks == 2)
- SDL_SetWindowFullscreen(vid_ctx.sdl_win, (fullscreen ^= 1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
- break;
- case SDL_WINDOWEVENT:
- switch(ev.window.event) {
- case SDL_WINDOWEVENT_SIZE_CHANGED: // keep video's aspect ratio
- SDL_RenderGetViewport(vid_ctx.sdl_ren, &view_tmp);
- vid_ctx.sdl_aspect_ratio.x = vid_ctx.sdl_aspect_ratio.y = 0
- , vid_ctx.sdl_aspect_ratio.w = view_tmp.w
- , vid_ctx.sdl_aspect_ratio.h = view_tmp.h;
- r = ((float)view_tmp.w / view_tmp.h) - ((float)vid_ctx.w_video / vid_ctx.h_video);
- if (r > 0.0f) {
- vid_ctx.sdl_aspect_ratio.w = (int)(((float)view_tmp.h / vid_ctx.h_video) * (float)vid_ctx.w_video);
- vid_ctx.sdl_aspect_ratio.x = (int)((float)(view_tmp.w - vid_ctx.sdl_aspect_ratio.w) * .5f);
- } else if (r < 0.0f) {
- vid_ctx.sdl_aspect_ratio.h = (int)(((float)view_tmp.w / vid_ctx.w_video) * (float)vid_ctx.h_video);
- vid_ctx.sdl_aspect_ratio.y = (int)((float)(view_tmp.h - vid_ctx.sdl_aspect_ratio.h) * .5f);
- }
- break;
- case SDL_WINDOWEVENT_RESIZED:
- sdl_renderer_change(&vid_ctx);
- case SDL_WINDOWEVENT_EXPOSED:
- if (do_draw == 0)
- do_draw = 2;
- default:
- break;
- }
- break;
- case SDL_RENDER_DEVICE_RESET:
- // note SDL : Must ignore existing textures pointers(all is lost), and recreate and reload all textures
- if (vid_ctx.sdl_text != NULL)
- vid_ctx.sdl_text = SDL_CreateTexture(vid_ctx.sdl_ren, vid_ctx.vid_sdl_format
- , SDL_TEXTUREACCESS_STREAMING, vid_ctx.w_frame, vid_ctx.h_frame);
- case SDL_RENDER_TARGETS_RESET:
- // note SDL : The render targets have been reset and their contents need to be updated
- // , the textures are re-allocated but the image data in them is lost.
- if (do_draw == 0)
- do_draw = 2;
- break;
- default:
- if (ev.type == vid_ctx.vid_sdl_event) {
- if (ev.user.code == 2) {
- if (do_draw != 1)
- do_draw = 1;
- else
- printf("[x] SDL dropped a frame\n");
- }
- else if (ev.user.code == 1) {
- SDL_SetWindowSize(vid_ctx.sdl_win, vid_ctx.w_video, vid_ctx.h_video);
- vid_ctx.sdl_text = SDL_CreateTexture( vid_ctx.sdl_ren, vid_ctx.vid_sdl_format
- , SDL_TEXTUREACCESS_STREAMING, vid_ctx.w_frame, vid_ctx.h_frame);
- }
- }
- break;
- } // end of switch(ev.type)
- } // end of while poll sdl event
- if (do_draw != 0) {
- do_draw = 0;
- sdl_draw_frame(&vid_ctx);
- }
- // wait for the next frame
- SDL_LockMutex(vid_ctx.sdl_gui_cond_lock);
- if (!vid_ctx.sdl_gui_conditioned)
- SDL_CondWaitTimeout(vid_ctx.sdl_gui_cond, vid_ctx.sdl_gui_cond_lock, 100);
- vid_ctx.sdl_gui_conditioned = SDL_FALSE;
- SDL_UnlockMutex(vid_ctx.sdl_gui_cond_lock);
- }
- // Stop and clean up libVLC.
- libvlc_media_player_stop(vid_ctx.vlc_mp);
- libvlc_media_player_release(vid_ctx.vlc_mp);
- libvlc_release(vid_ctx.vlc_inst);
- // Close window and clean up libSDL.
- SDL_DestroyMutex(vid_ctx.vid_lock);
- SDL_DestroyMutex(vid_ctx.sdl_gui_cond_lock);
- SDL_DestroyCond(vid_ctx.sdl_gui_cond);
- if (vid_ctx.vid_data)
- SDL_free(vid_ctx.vid_data);
- if (vid_ctx.sdl_text)
- SDL_DestroyTexture(vid_ctx.sdl_text);
- SDL_DestroyRenderer(vid_ctx.sdl_ren);
- SDL_DestroyWindow(vid_ctx.sdl_win);
- SDL_Quit();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement