EasyPlayerPro for Windowsæ¯åºäºffmpegè¿è¡å¼åçå ¨åè½ææ¾å¨ï¼å¼åè¿ç¨ä¸åèäºå¾å¤å¼æºçææ¾å¨ï¼è¯¸å¦vlcåffplayçï¼å ¶ä¸æ强大çè«è¿äºvlcï¼ä½æ¯é´äºvlcæ¡æ¶è¿äºåºå¤§èå ¶ä¸ä»åå¨è¯¸å¤é®é¢èèå¼äºï¼èå ¶ä»çæ´å¾åäºæ¼ç¤ºdemoï¼åªè½æä¾é¨ååé´æä¹ï¼æ èï¼EasyPlayerPro ä¸è´¯ç§æ¿Easyç³»åå°èç²¾ï¼æ¥å£ç®ååè½å¼ºå¤§çå®æ¨ä»æ°è®¾è®¡äºä¸å¥æ¡æ¶ï¼è¯¥å¥æ¡æ¶è½éåºå¤çº¿ç¨è°ç¨ä»¥åå¤ä¸ªææ¾å®ä¾åæ¶è¿è¡ï¼åEasyPlayerä¸æ ·Easy; å½ç¶ï¼å¨æ¤ä¹ééçæè°¢å大å¼æºææ¾å¨ä»¥åffmpegçä½è çæ ç§å¥ç®ã
EasyPlayerProå为ä¸å¤§æ¨¡åï¼æå¼æ¨¡åï¼è¯»åæµæ°æ®æ¨¡åï¼è§£ç 模åå渲æ模åï¼å ¶ä¸ï¼
(1) æå¼æ¨¡å
æå¼æµæ¨¡åå¾ç®åï¼æç§ä¹¦å¼çè°ç¨æ¹æ³ï¼
player->avformat_context = avformat_alloc_context();
player->avformat_context->interrupt_callback.callback = interrupt_cb;
player->avformat_context->interrupt_callback.opaque = player;
// open input file
AVDictionary *options = NULL;
//av_dict_set(&options, "rtsp_transport", "udp", );
if (avformat_open_input(&player->avformat_context, url, fmt, &options) != )
{
goto error_handler;
}
// find stream info
if (avformat_find_stream_info(player->avformat_context, NULL) < )
{
goto error_handler;
}
// set current audio & video stream
for (i=,idx=-,cur=-; i<(int)player->avformat_context->nb_streams; i++) {
switch (type) {
case AVMEDIA_TYPE_AUDIO:
// get last codec context
if (player->acodec_context) {
lastctxt = player->acodec_context;
}
// get new acodec_context & astream_timebase
player->acodec_context = player->avformat_context->streams[idx]->codec;
player->astream_timebase = player->avformat_context->streams[idx]->time_base;
// reopen codec
if (lastctxt) avcodec_close(lastctxt);
decoder = avcodec_find_decoder(player->acodec_context->codec_id);
if (decoder && avcodec_open2(player->acodec_context, decoder, NULL) == ) {
player->astream_index = idx;
}
else {
av_log(NULL, AV_LOG_WARNING, "failed to find or open decoder for audio !\n");
player->astream_index = -;
}
break;
case AVMEDIA_TYPE_VIDEO:
// get last codec context
if (player->vcodec_context) {
lastctxt = player->vcodec_context;
}
// get new vcodec_context & vstream_timebase
player->vcodec_context = player->avformat_context->streams[idx]->codec;
player->vstream_timebase = player->avformat_context->streams[idx]->time_base;
// reopen codec
if (lastctxt) avcodec_close(lastctxt);
decoder = avcodec_find_decoder(player->vcodec_context->codec_id);
if (decoder && avcodec_open2(player->vcodec_context, decoder, NULL) == ) {
player->vstream_index = idx;
}
else {
av_log(NULL, AV_LOG_WARNING, "failed to find or open decoder for video !\n");
player->vstream_index = -;
}
break;
case AVMEDIA_TYPE_SUBTITLE:
return -; // todo...
}
}
if (idx == -) return -;
// for audio
if (player->astream_index != -)
{
arate = player->acodec_context->sample_rate;
aformat = player->acodec_context->sample_fmt;
alayout = player->acodec_context->channel_layout;
//++ fix audio channel layout issue
if (alayout == ) {
alayout = av_get_default_channel_layout(player->acodec_context->channels);
}
//-- fix audio channel layout issue
}
// for video
if (player->vstream_index != -) {
vrate = player->avformat_context->streams[player->vstream_index]->r_frame_rate;
if (vrate.num / vrate.den >= ) {
vrate.num = ;
vrate.den = ;
}
player->vcodec_context->pix_fmt = vformat;
width = player->vcodec_context->width;
height = player->vcodec_context->height;
}
é¦å ï¼avformat_open_inputæå¼ä¸ä¸ªæµï¼ä¸ºäºé¿å å¨æå¼æµçæ¶ååºç°é»å¡ï¼æ们å建ä¸ä¸ªçº¿ç¨æ¥æ§è¡ï¼åæ¶ï¼ä¸ºäºé²æ¢ffmpegå é¨åºç°æä¹ è¡çé»å¡ï¼æä»¬ä¼ å ¥é»å¡åè°å½æ°ï¼å¨å ³éæµæè å ¶ä»å¿ è¦çæ¶å解é¤é»å¡ï¼avformat_find_stream_infoè·åæµç解ç ä¿¡æ¯ï¼æ ¹æ®é³è§é¢ä»¥ååå¹ç解ç ä¿¡æ¯åå§å解ç å¨ï¼
(2) 读åæµæ°æ®æ¨¡å
retv = av_read_frame(player->avformat_context, packet);
//++ play completed ++//
if (retv < )
{
if (player->avformat_context->pb && player->avformat_context->pb->error)
{
//åç¥ææ¾å®æ¶æµä¸æ
player->error_flag = ;
//å建æ线éè¿é误æ£æµçº¿ç¨
// [9/4/2017 swordtwelve]
break;
}
player->player_status |= PS_D_PAUSE;
pktqueue_write_post_i(player->pktqueue, packet);
usleep(*);
continue;
}
//-- play completed --//
player->error_flag = ;//-1=åå§å 0=æ£å¸¸ 1-né误代ç
// audio
if (packet->stream_index == player->astream_index)
{
pktqueue_write_post_a(player->pktqueue, packet);
}
// video
if (packet->stream_index == player->vstream_index)
{
pktqueue_write_post_v(player->pktqueue, packet);
}
if ( packet->stream_index != player->astream_index
&& packet->stream_index != player->vstream_index )
{
av_packet_unref(packet); // free packet
pktqueue_write_post_i(player->pktqueue, packet);
}
}
读åæ°æ®æ¨¡åè¶ çº§ç®åï¼å建ä¸ä¸ªçº¿ç¨å¾ªç¯æ§è¡av_read_frameï¼è¯»åå°ä¸å¸§å°±å°å ¶æ¾å ¥éåï¼è¿ééç¨äºffplayçé»å¡çæ¹å¼æ¥å¤çéåçæ¶è´¹è åç产è çé®é¢ï¼è¿åæå¾ ä¼åï¼åç»å°æ¹ææ é循ç¯éå模å¼ï¼å¦EasyPlayerã
(3) 解ç 模å
解ç 模åå为é³é¢åè§é¢è§£ç 模åï¼é³è§é¢ç解ç æµç¨é常ç¸ä¼¼ï¼
主è¦å为ä¸æ¥ï¼
a. ä»éåä¸è¯»åé³è§é¢ç¼ç æ°æ®ï¼
b. é³è§é¢åå«éç¨avcodec_decode_audio4åavcodec_decode_video2è¿è¡è§£ç ï¼
c. é³è§é¢æ¸²æï¼
è¿éçé讲解è§é¢ç解ç åçè¿ç¨ï¼å ¶ä¸æ¶åå°è§£ç åçåå§å¾åæ°æ®è¿è¡å¤çï¼è§£ç åºä¸å¸§å¾å以åï¼æ们éè¦å¯¹å ¶è¿è¡åå¹åå¾åæè å ¶ä»çè§é¢å¾åçå å ï¼åå©ffmpeg强大çå¾å转æ¢å缩æ¾è½åï¼åå©VFXåºæ们å¾å®¹æå®ç°ï¼
consumed = avcodec_decode_video2(player->vcodec_context, vframe, &gotvideo, packet);
if (consumed < ) {
av_log(NULL, AV_LOG_WARNING, "an error occurred during decoding video.\n");
break;
}
if (gotvideo)
{
// 解ç è§é¢å¸§æ·»å ç¹æå¤ç [9/7/2017 dingshuai]
// 1. å å å¾ç
// 2. å å åæ¯
// 3. ç»æ¡...
// 对解ç 帧è¿è¡ç¹æå¤çï¼å符ï¼å¾çå å ï¼æ·»å ç¹æï¼ [Dingshuai 2017/08/07]
#if
WaterMarkInfo g_waterMarkInfo = player->vfxConfigInfo.warkMarkInfo;
if (g_waterMarkInfo.bIsUseWaterMark)
{
if (player->vcodec_context->width != vframe->width ||
player->vcodec_context->height != vframe->height ||
player->vfxConfigInfo.warkMarkInfo.bResetWaterMark )
{
//åå§åæ°´å°å å
//;表示å°æ ä½ç½®ï¼1 == å·¦ä¸ 2 == å³ä¸ 3 == å·¦ä¸ 4 == å³ä¸
//eWaterMarkPos = 3
//;æ°´å°é¡¶ç¹xè½´åæ ï¼å»ºè®®ä¸å°äº0ï¼ä¸å¤§äºè§é¢å®½åº¦
//nLeftTopX = 0
//;æ°´å°é¡¶ç¹yè½´åæ ï¼å»ºè®®ä¸å°äº0ï¼ä¸å¤§äºè§é¢é«åº¦
//nLeftTopY = 480
//;æ°´å°é£æ ¼ï¼0 - 6
//eWatermarkStyle = 3
//;æ°´å°å¾åæ件路å¾LOGO.png
//strWMFilePath = .\Res\logo.png
switch (g_waterMarkInfo.eWaterMarkPos)
{
case POS_LEFT_TOP:
g_waterMarkInfo.nLeftTopX = ;
g_waterMarkInfo.nLeftTopY = ;
break;
case POS_RIGHT_TOP:
g_waterMarkInfo.nLeftTopX = vframe->width;
g_waterMarkInfo.nLeftTopY = ;
break;
case POS_LEFT_BOTTOM:
g_waterMarkInfo.nLeftTopX = ;
g_waterMarkInfo.nLeftTopY = vframe->height;
break;
case POS_RIGHT_BOTTOM:
g_waterMarkInfo.nLeftTopX = vframe->width;
g_waterMarkInfo.nLeftTopY = vframe->height;
break;
}
player->vfxHandle->SetVideoInVideoParam( , , , vframe->width,
vframe->height, , , );
player->vfxHandle->SetLogoImage(g_waterMarkInfo.strWMFilePath, g_waterMarkInfo.nLeftTopX,
g_waterMarkInfo.nLeftTopY, g_waterMarkInfo.bIsUseWaterMark, g_waterMarkInfo.eWatermarkStyle);
player->vfxConfigInfo.warkMarkInfo.bResetWaterMark = FALSE;
}
}
//åå§ååå¹ä¿¡æ¯
VideoTittleInfo tittleInfo = player->vfxConfigInfo.tittleInfo;
if(tittleInfo.bResetTittleInfo)
{
// -->1ãåå§åå建åå¹æé,并åå§åè§é¢é¿å®½åæ° m_pVideoVfxMakerInfo->nDesWidth, m_pVideoVfxMakerInfo->nDesHeight, m_pVideoVfxMakerInfo->strDesBytesType);
player->vfxHandle->CreateOverlayTitle(vframe->width, vframe->height, ("YUY2"));
// -->2ã设置åå¹æåä¿¡æ¯
LOGFONTA inFont;
inFont.lfHeight = tittleInfo.nTittleHeight;
inFont.lfWidth = tittleInfo.nTittleWidth;
inFont.lfEscapement = ;
inFont.lfOrientation = ;
inFont.lfWeight = tittleInfo.nFontWeight;//FW_NORMAL;
inFont.lfItalic = ;
inFont.lfUnderline = ;
inFont.lfStrikeOut = ;
inFont.lfCharSet =GB2312_CHARSET;// ANSI_CHARSET;//134
inFont.lfOutPrecision =;// OUT_DEFAULT_PRECIS;
inFont.lfClipPrecision = ;//CLIP_DEFAULT_PRECIS;
inFont.lfQuality = ;//PROOF_QUALITY;
inFont.lfPitchAndFamily = ;//49;//49
strcpy(inFont.lfFaceName, tittleInfo.strFontType);//"åææ°é");//"åæé¶ä¹¦");"é¶ä¹¦"
POINT pointTitle;
if(tittleInfo.nMoveType==)
{
pointTitle= tittleInfo.ptStartPosition;
if(pointTitle.x<=) pointTitle.x=;
if(pointTitle.x>=vframe->width) pointTitle.x=vframe->width/;
}
else if(tittleInfo.nMoveType==)//ä»å·¦å¾å³
{
pointTitle.x = -;
pointTitle.y = tittleInfo.ptStartPosition.y;
}
else if(tittleInfo.nMoveType==)
{
pointTitle.x = vframe->width+;
pointTitle.y = tittleInfo.ptStartPosition.y;
}
player->vfxHandle->SetOverlayTitleInfo(tittleInfo.strTittleContent,
inFont, tittleInfo.nColorR, tittleInfo.nColorG,
tittleInfo.nColorB, pointTitle);
//-->3ã设置åå¹è¿è¡æç¶æ
player->vfxHandle->SetOverlayTitleState(tittleInfo.nState);
player->vfxConfigInfo.tittleInfo.bResetTittleInfo = FALSE;
}
if (player->vfxHandle && (g_waterMarkInfo.bIsUseWaterMark || tittleInfo.nState))//logo-æ°´å° + åå¹ + ï¼ï¼ï¼
{
if (player->vcodec_context->width != vframe->width ||
player->vcodec_context->height != vframe->height )
{
if (pVfxBuffer)
{
free(pVfxBuffer);
pVfxBuffer = NULL;
}
}
int nBufSize = vframe->width*vframe->height << ;
if (!pVfxBuffer)
{
pVfxBuffer = (BYTE*)malloc(nBufSize); //ç¼ååå
¥æºæ°æ®
memset(pVfxBuffer, , nBufSize);
}
AVFrame src;
av_image_fill_arrays(src.data, src.linesize, pVfxBuffer, outPixelFormat, vframe->width, vframe->height, );
//YUV420 -> YUY2
ConvertColorSpace(&src, outPixelFormat, vframe, inPixelFormat, vframe->width, vframe->height);
// av_image_copy_to_buffer(pVfxBuffer, nBufSize,
// vframe->data, vframe->linesize, AV_PIX_FMT_YUYV422, vframe->width, vframe->height, 1);
//æ°´å°å å
if(g_waterMarkInfo.bIsUseWaterMark)
player->vfxHandle->AddWaterMask(pVfxBuffer);
//OSDå å
if(tittleInfo.nState)
player->vfxHandle->DoOverlayTitle(pVfxBuffer);
//YUY2 -> I420
//ConvertColorSpace(vframe, inPixelFormat, &src, outPixelFormat, vframe->width, vframe->height);
av_image_fill_arrays(vframe->data, vframe->linesize, pVfxBuffer, outPixelFormat, vframe->width, vframe->height, );
int nPixelFmt = AV_PIX_FMT_YUYV422;
player_setparam(player, PARAM_RENDER_OUTFORMAT, &nPixelFmt);
}
else
{
int nPixelFmt = AV_PIX_FMT_YUV420P;
player_setparam(player, PARAM_RENDER_OUTFORMAT, &nPixelFmt);
}
#endif
ç±äºè§é¢æ¸²æéè¦ä¸å®çæ¶é´ï¼æ们ä¹å°è§£ç 帧æ°æ®è¿å ¥éåè¿è¡ç¼åï¼ä»èä¿è¯ææ¾çæµç æ§ï¼
(4) 渲æ模å
渲æ模åå为é³é¢æ¸²æåè§é¢æ¸²æï¼é³é¢æ¸²æå³ææ¾ï¼ä½¿ç¨waveOutOpenï¼waveOutWriteçwaveoutå½æ°å³å¯å®ç°ï¼ä¸é¢éç¹è¯´ä¸ä¸è§é¢æ¸²æï¼è§é¢æ¸²æéä¿è®²ä¹å°±æ¯å¾åç»å¶ï¼Windowså¹³å°å¯éç¨D3D,DDraw, GDIï¼OpenGLçå¤ç§æ¹å¼è¿è¡åç°ï¼æ¬æ主è¦éç¨3ç§æ¸²ææ¹å¼ï¼D3Dï¼GDIåOpenGLï¼
为äºä¿è¯æ¸²æçæµç æ§ï¼æ们å建线ç¨æ§è¡æ¸²æï¼
a. 读å解ç å¾åéåï¼
b. é³è§é¢æ¶é´æ³åæ¥å¤çï¼
c. D3D/gdi/openGL渲æï¼
å ³äºEasyPlayerPro
EasyPlayerProæ¯ä¸æ¬¾å ¨åè½çæµåªä½ææ¾å¨ï¼æ¯æRTSPãRTMPãHTTPãHLSãUDPãRTPçå¤ç§æµåªä½åè®®ææ¾ãæ¯ææ¬å°æ件ææ¾ï¼æ¯ææ¬å°ææãæ¬å°å½åãææ¾æ转ãå¤å±ææ¾çå¤ç§åè½ç¹æ§ï¼ç¨³å®ãé«æãå¯é ï¼æ¯æWindowsãAndroidãiOSä¸ä¸ªå¹³å°ï¼ç®åå¨å¤å®¶æè²ãå®é²ãè¡ä¸åå ¬å¸ï¼é½å¾å°çåºç¨ï¼å¹¿å好è¯ï¼
EasyPlayerProï¼https://github.com/EasyDSS/EasyPlayerPro
ç¹å»é¾æ¥å å ¥ç¾¤ãEasyPlayer & EasyPlayerProãï¼544917793
è·åæ´å¤ä¿¡æ¯
é®ä»¶ï¼[email protected]
WEBï¼www.EasyDarwin.org
Copyright © EasyDarwin.org 2012-2017