mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 18:50:20 +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)
|
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})
|
foreach(TEST_SRC ${TEST_SRC_LIST})
|
||||||
STRING(REGEX REPLACE ".cpp" "" TEST_EXE_NAME ${TEST_SRC})
|
STRING(REGEX REPLACE ".cpp" "" TEST_EXE_NAME ${TEST_SRC})
|
||||||
STRING(REGEX REPLACE "./" "" TEST_EXE_NAME ${TEST_EXE_NAME})
|
STRING(REGEX REPLACE "./" "" TEST_EXE_NAME ${TEST_EXE_NAME})
|
||||||
@ -36,4 +67,23 @@ if(MYSQL_FOUND)
|
|||||||
target_link_libraries(${TEST_EXE_NAME} mysqlclient)
|
target_link_libraries(${TEST_EXE_NAME} mysqlclient)
|
||||||
endif(MYSQL_FOUND)
|
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})
|
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