添加播放器测试程序

This commit is contained in:
xzl 2017-05-08 18:03:43 +08:00
parent e5621efc92
commit b646355545
6 changed files with 315 additions and 0 deletions

12
cmake/FindAVCODEC.cmake Normal file
View File

@ -0,0 +1,12 @@
find_path(AVCODEC_INCLUDE_DIR
NAMES libavcodec/avcodec.h)
find_library(AVCODEC_LIBRARY
NAMES avcodec)
set(AVCODEC_LIBRARIES ${AVCODEC_LIBRARY})
set(AVCODEC_INCLUDE_DIRS ${AVCODEC_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AVCODEC DEFAULT_MSG AVCODEC_LIBRARY AVCODEC_INCLUDE_DIR)

12
cmake/FindAVUTIL.cmake Normal file
View File

@ -0,0 +1,12 @@
find_path(AVUTIL_INCLUDE_DIR
NAMES libavutil/avutil.h)
find_library(AVUTIL_LIBRARY
NAMES avutil)
set(AVUTIL_LIBRARIES ${AVUTIL_LIBRARY})
set(AVUTIL_INCLUDE_DIRS ${AVUTIL_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AVUTIL DEFAULT_MSG AVUTIL_LIBRARY AVUTIL_INCLUDE_DIR)

View File

@ -1,4 +1,35 @@
#SDL
find_package(SDL QUIET)
if(SDL_FOUND)
include_directories(${SDL_INCLUDE_DIR})
message(STATUS "找到SDL")
endif(SDL_FOUND)
#ffmpeg/libutil
find_package(AVUTIL QUIET)
if(AVUTIL_FOUND)
include_directories(${AVUTIL_INCLUDE_DIR})
message(STATUS "找到libutil")
endif(AVUTIL_FOUND)
#ffmpeg/libavcodec
find_package(AVCODEC QUIET)
if(AVCODEC_FOUND)
include_directories(${AVCODEC_INCLUDE_DIR})
message(STATUS "找到libavcodec")
endif(AVCODEC_FOUND)
aux_source_directory(. TEST_SRC_LIST)
#ffmpeg/libavcodec ffmpeg/libavcodec SDL test_player
if(SDL_FOUND AND AVCODEC_FOUND AND AVUTIL_FOUND)
message(STATUS "test_player被编译")
else(SDL_FOUND AND AVCODEC_FOUND AND AVUTIL_FOUND)
message(STATUS "test_player被忽略,如需编译请先安装sdl ffmpeg/libavcodec ffmpeg/libavcodec")
list(REMOVE_ITEM TEST_SRC_LIST ./test_player.cpp)
endif(SDL_FOUND AND AVCODEC_FOUND AND AVUTIL_FOUND)
foreach(TEST_SRC ${TEST_SRC_LIST})
STRING(REGEX REPLACE ".cpp" "" TEST_EXE_NAME ${TEST_SRC})
STRING(REGEX REPLACE "./" "" TEST_EXE_NAME ${TEST_EXE_NAME})
@ -36,4 +67,23 @@ if(MYSQL_FOUND)
target_link_libraries(${TEST_EXE_NAME} mysqlclient)
endif(MYSQL_FOUND)
#link test_player
if(TEST_EXE_NAME STREQUAL test_player)
target_link_libraries(${TEST_EXE_NAME} SDL avcodec avutil)
endif(TEST_EXE_NAME STREQUAL test_player)
endforeach(TEST_SRC ${TEST_SRC_LIST})

84
tests/H264Decoder.h Normal file
View File

@ -0,0 +1,84 @@
/*
* H264Decoder.h
*
* Created on: 20161221
* Author: xzl
*/
#ifndef H264Decoder_H_
#define H264Decoder_H_
#include <string>
#include <memory>
#include <stdexcept>
#ifdef __cplusplus
extern "C" {
#endif
//#include "libavutil/mathematics.h"
#include "libavcodec/avcodec.h"
//#include "libswscale/swscale.h"
#ifdef __cplusplus
}
#endif
using namespace std;
namespace ZL {
namespace Codec {
class H264Decoder
{
public:
H264Decoder(void){
avcodec_register_all();
AVCodec *pCodec = avcodec_find_decoder(CODEC_ID_H264);
if (!pCodec) {
throw std::runtime_error("未找到H264解码器");
}
m_pContext.reset(avcodec_alloc_context3(pCodec), [](AVCodecContext *pCtx) {
avcodec_close(pCtx);
avcodec_free_context(&pCtx);
});
if (!m_pContext) {
throw std::runtime_error("创建解码器失败");
}
if (pCodec->capabilities & CODEC_CAP_TRUNCATED) {
/* we do not send complete frames */
m_pContext->flags |= CODEC_FLAG_TRUNCATED;
}
if(avcodec_open2(m_pContext.get(), pCodec, NULL)< 0){
throw std::runtime_error("打开编码器失败");
}
m_pFrame.reset(av_frame_alloc(),[](AVFrame *pFrame){
av_frame_free(&pFrame);
});
if (!m_pFrame) {
throw std::runtime_error("创建帧缓存失败");
}
}
virtual ~H264Decoder(void){}
bool inputVideo(unsigned char* data,unsigned int dataSize,uint32_t ui32Stamp,AVFrame **ppFrame){
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = data;
pkt.size = dataSize;
pkt.dts = ui32Stamp;
int iGotPicture ;
auto iLen = avcodec_decode_video2(m_pContext.get(), m_pFrame.get(), &iGotPicture, &pkt);
if (!iGotPicture || iLen < 0) {
return false;
}
*ppFrame = m_pFrame.get();
return true;
}
private:
std::shared_ptr<AVCodecContext> m_pContext;
std::shared_ptr<AVFrame> m_pFrame;
};
} /* namespace Codec */
} /* namespace ZL */
#endif /* H264Decoder_H_ */

79
tests/YuvDisplayer.h Normal file
View File

@ -0,0 +1,79 @@
/*
* YuvDisplayer.h
*
* Created on: 20161221
* Author: xzl
*/
#ifndef YUVDISPLAYER_H_
#define YUVDISPLAYER_H_
#include <stdexcept>
#include "Util/onceToken.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <SDL/SDL.h>
#include <libavcodec/avcodec.h>
#ifdef __cplusplus
}
#endif
namespace ZL {
namespace Screen {
class YuvDisplayer {
public:
YuvDisplayer(){
static onceToken token([]() {
if(SDL_Init(SDL_INIT_EVERYTHING) == -1) {
throw std::runtime_error("初始化SDL失败");
}
}, []() {
SDL_Quit();
});
}
virtual ~YuvDisplayer(){
if(m_pOverlay){
SDL_FreeYUVOverlay(m_pOverlay);
}
}
bool displayYUV(AVFrame *pFrame){
if (!m_pScreen) {
/* Set up the screen */
m_pScreen = SDL_SetVideoMode(1366, 768, 16, SDL_SWSURFACE);
}
if (!m_pOverlay && m_pScreen) {
/* Create a YUV overlay */
m_pOverlay = SDL_CreateYUVOverlay(pFrame->width, pFrame->height, SDL_YV12_OVERLAY, m_pScreen);
/* Set the window caption */
SDL_WM_SetCaption("YUV Window", NULL);
}
if (m_pOverlay) {
/* Apply the image to the screen */
m_pOverlay->pixels[0] = pFrame->data[0];
m_pOverlay->pixels[2] = pFrame->data[1];
m_pOverlay->pixels[1] = pFrame->data[2];
m_pOverlay->pitches[0] = pFrame->linesize[0];
m_pOverlay->pitches[2] = pFrame->linesize[1];
m_pOverlay->pitches[1] = pFrame->linesize[2];
/* Update the screen */
SDL_Rect rect = { 0 ,0 ,1366,768};
SDL_LockYUVOverlay(m_pOverlay);
SDL_DisplayYUVOverlay(m_pOverlay, &rect);
SDL_UnlockYUVOverlay(m_pOverlay);
return true;
}
return false;
}
private:
SDL_Surface* m_pScreen = nullptr;
SDL_Overlay* m_pOverlay = nullptr;
};
} /* namespace Screen */
} /* namespace ZL */
#endif /* YUVDISPLAYER_H_ */

78
tests/test_player.cpp Normal file
View File

@ -0,0 +1,78 @@
#include <signal.h>
#include <unistd.h>
#include "Util/logger.h"
#include <iostream>
#include "Poller/EventPoller.h"
#include "Rtsp/UDPServer.h"
#include "Util/onceToken.h"
#include "Device/PlayerProxy.h"
#include "H264Decoder.h"
#include "YuvDisplayer.h"
#include "Network/sockutil.h"
using namespace std;
using namespace ZL::Screen;
using namespace ZL::Codec;
using namespace ZL::Util;
using namespace ZL::Thread;
using namespace ZL::Network;
using namespace ZL::Rtsp;
using namespace ZL::DEV;
void programExit(int arg) {
EventPoller::Instance().shutdown();
}
int main(int argc, char *argv[]){
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
//Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
signal(SIGINT, programExit);
if(argc != 5){
FatalL << "\r\n测试方法:./test_player rtxp_url rtsp_user rtsp_pwd rtp_type\r\n"
<< "例如:./test_player rtsp://127.0.0.1/live/0 admin 123456 0\r\n"
<<endl;
Logger::Destory();
return 0;
}
MediaPlayer::Ptr player(new MediaPlayer());
player->setOnPlayResult([](const SockException &ex) {
InfoL << "OnPlayResult:" << ex.what();
});
player->setOnShutdown([](const SockException &ex) {
ErrorL << "OnShutdown:" << ex.what();
});
//DebugL << argv[1] << " " << argv[2] << " " << argv[3] << " " << argv[4] << endl;
player->play(argv[1],argv[2],argv[3],(PlayerBase::eRtpType)atoi(argv[4]));
H264Decoder decoder;
YuvDisplayer displayer;
ThreadPool pool(1);
player->setOnVideoCB([&](const H264Frame &frame){
pool.async([&,frame]() {
AVFrame *pFrame = nullptr;
bool flag = decoder.inputVideo((unsigned char *)frame.data.data(), frame.data.size() ,frame.timeStamp, &pFrame);
if(flag) {
//DebugL << pFrame->pkt_pts;
displayer.displayYUV(pFrame);
}
});
});
EventPoller::Instance().runLoop();
static onceToken token(nullptr, []() {
UDPServer::Destory();
AsyncTaskThread::Destory();
EventPoller::Destory();
Logger::Destory();
});
return 0;
}