Linux上实现:
运行下面代码前确保Linux上已经安装好vlc以及相应插件,我编译并安装了vlc-2.0.1版本,但最终仍然不能打开rtsp视频流,不清楚原因,但是本地视频还是可以获取到原始视频流的。
代码里面用到了SDL来显示视频,我下载并编译安装了SDL-1.2.15的源码。
/* libSDL and libVLC sample code * Copyright ? 2008 Sam Hocevar <sam@zoy.org> * license: [http://en.wikipedia.org/wiki/WTFPL WTFPL] */ #include <stdio.h> #include <stdint.h> #include <math.h> #include <stdlib.h> #include <assert.h> #include <SDL/SDL.h> #include <SDL/SDL_mutex.h> #include <vlc/vlc.h> #define WIDTH 640 #define HEIGHT 480 #define VIDEOWIDTH 320 #define VIDEOHEIGHT 240 struct ctx { SDL_Surface *surf; SDL_mutex *mutex; }; static void *lock(void *data, void **p_pixels) { #if 1 struct ctx *ctx = data; SDL_LockMutex(ctx->mutex); SDL_LockSurface(ctx->surf); *p_pixels = ctx->surf->pixels; #endif return NULL; /* picture identifier, not needed here */ } static void unlock(void *data, void *id, void *const *p_pixels) { #if 1 struct ctx *ctx = data; /* VLC just rendered the video, but we can also render stuff */ uint16_t *pixels = *p_pixels; int x, y; //memset(pixels, 0x00, 320*240); for(y = 10; y < 40; y++) for(x = 10; x < 40; x++) if(x < 13 || y < 13 || x > 36 || y > 36) pixels[y * VIDEOWIDTH + x] = 0xffff; else pixels[y * VIDEOWIDTH + x] = 0x0; #if 0 FILE *fp = NULL; fp = fopen("data.yuv", "ab+"); if(fp != NULL) { fwrite(pixels, 320*240*3, 1, fp); fclose(fp); printf("write a frame.\r\n"); } #endif SDL_UnlockSurface(ctx->surf); SDL_UnlockMutex(ctx->mutex); assert(id == NULL); /* picture identifier, not needed here */ #endif } static void display(void *data, void *id) { /* VLC wants to display the video */ (void) data; printf("display a frame.\r\n"); assert(id == NULL); } int main(int argc, char *argv[]) { libvlc_instance_t *libvlc; libvlc_media_t *m; libvlc_media_player_t *mp; char const *vlc_argv[] = { "--no-audio", /* skip any audio track */ "--no-xlib", /* tell VLC to not use Xlib */ }; int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv); SDL_Surface *screen, *empty; SDL_Event event; SDL_Rect rect; 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_AUDIO | SDL_INIT_EVENTTHREAD) == -1) { printf("cannot initialize SDL\n"); return EXIT_FAILURE; } empty = SDL_CreateRGBSurface(SDL_SWSURFACE, VIDEOWIDTH, VIDEOHEIGHT, 16, 0, 0, 0, 0); #if 1 ctx.surf = SDL_CreateRGBSurface(SDL_SWSURFACE, VIDEOWIDTH, VIDEOHEIGHT, 16, 0x001f, 0x07e0, 0xf800, 0); #else ctx.surf = SDL_CreateRGBSurface(SDL_SWSURFACE, VIDEOWIDTH, VIDEOHEIGHT, 16, 0xff000000, 0x00ff0000, 0x0000ff00, 0); #endif ctx.mutex = SDL_CreateMutex(); int options = SDL_ANYFORMAT | SDL_HWSURFACE | SDL_DOUBLEBUF; 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]); 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(mp, "RV16", VIDEOWIDTH, VIDEOHEIGHT, VIDEOWIDTH*2); libvlc_media_player_play(mp); /* * Main loop */ rect.w = 0; rect.h = 0; 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; } rect.x = (int)((1. + .5 * sin(0.03 * n)) * (WIDTH - VIDEOWIDTH) / 2); rect.y = (int)((1. + .5 * cos(0.03 * n)) * (HEIGHT - VIDEOHEIGHT) / 2); if(!pause) n++; /* 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, &rect); SDL_UnlockMutex(ctx.mutex); SDL_Flip(screen); SDL_Delay(10); SDL_BlitSurface(empty, NULL, screen, &rect); } /* * 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); SDL_FreeSurface(ctx.surf); SDL_FreeSurface(empty); SDL_Quit(); return 0; } |
Windows上的实现:
上面提到的VLC的插件和SDL,在Windows上同样需要,我用vlc2.0.1在Linux上编译了windows版本的vlc,这样相应的库和插件就都有了,SDL可以到官网下载。
由于vlc的哪个头文件中包含了stdint.h这个头文件,这个头文件说是C99标准头文件,vc里面没有,vs2010里面有,所以用vs2010创建的工程,在工程中添加好vlc和SDL的include、lib。并且将vlc和SDL相应用到的DLL文件复制到工程的Debug或Release目录,还要将vlc的plugins目录复制到Debug或Release目录,要不然找不到vlc插件。
#include
"stdafx.h"
#include
<stdio.h>
#include
<tchar.h>
#include
<time.h>
#include
<windows.h>
#include
<stdlib.h>
#include
<assert.h>
#include
<SDL.h>
#include
<vlc/vlc.h>
#pragma
comment
(
lib
,
"libvlc.lib"
)
#pragma
comment
(
lib
,
"libvlccore.lib"
)
#pragma
comment
(
lib
,
"SDL.lib"
)
using
namespace
std;
#if
0 //这部分代码是读取本地文件然后显示,并没有用到SDL
int
_tmain(
int
argc, _TCHAR* argv[])
{
libvlc_instance_t * vlc_ins = NULL;
libvlc_media_player_t * vlc_player = NULL;
libvlc_media_t * vlc_media = NULL;
const
char
* vlc_args[] =
{
"-I"
,
"dummy"
,
"--ignore-config"
,
"--extraintf=logger"
,
"--verbose=2"
,
|