mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 02:34:26 +08:00
添加播放器测试程序
This commit is contained in:
parent
e5621efc92
commit
b646355545
12
cmake/FindAVCODEC.cmake
Normal file
12
cmake/FindAVCODEC.cmake
Normal 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
12
cmake/FindAVUTIL.cmake
Normal 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)
|
@ -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
84
tests/H264Decoder.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* H264Decoder.h
|
||||
*
|
||||
* Created on: 2016年12月21日
|
||||
* 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
79
tests/YuvDisplayer.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* YuvDisplayer.h
|
||||
*
|
||||
* Created on: 2016年12月21日
|
||||
* 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
78
tests/test_player.cpp
Normal 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user