Browse Source

增加时间

master
JackLee_CN 1 year ago
parent
commit
70f5204b4c
  1. 18
      MediaFFex.h
  2. 2
      MediaSlider.h
  3. 58
      SDL2RenderWidget.cpp
  4. 4
      SDL2RenderWidget.h
  5. 82
      mediaplayer.cpp
  6. 49
      mediaplayer.h
  7. 34
      zffmpeg.cpp
  8. 5
      zffmpeg.h

18
MediaFFex.h

@ -54,12 +54,22 @@ typedef enum{
sw,
hw
}decoder_type;
/*缩放模式*/
typedef enum{
keep_aspect_ratio,
stretch_aspect_ratio
}sws_type;
typedef struct{
}u_opt;
typedef struct{
int width;
int height;
AVPixelFormat pix_fmt;
sws_type aspect_type;
decoder_type sw;
}s_opt;
}use_opt;
typedef struct{
}sys_opt;
#endif

2
MediaSlider.h

@ -9,8 +9,6 @@ class MediaSlider : public QSlider {
public:
explicit MediaSlider(QWidget *parent = nullptr);
void changeValue(int n);
signals:
/** 点击事件 */
void clicked(MediaSlider *slider);

58
SDL2RenderWidget.cpp

@ -64,7 +64,7 @@ void SDL2RenderWidget::renderer_default_image()
SDL_RenderPresent(m_sdl_renderer);
}
}
void SDL2RenderWidget::update_image(MediaAVFrame* v_frame, v_sws_spec *v_spec)
void SDL2RenderWidget::update_image(MediaAVFrame *v_frame, v_sws_spec *v_spec, use_opt *_opt)
{
m_renderer_image_type = media_video_image;
@ -80,15 +80,45 @@ void SDL2RenderWidget::update_image(MediaAVFrame* v_frame, v_sws_spec *v_spec)
}
m_sdl_texture = SDL_CreateTexture(m_sdl_renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,
v_frame->m_frame->width, v_frame->m_frame->height);
SDL_SetWindowSize(m_sdl_window, v_frame->m_frame->width, v_frame->m_frame->height);
//改变播放器窗口同帧一样大
emit signals_change_size(v_frame->m_frame->width, v_frame->m_frame->height);
}
SDL_GetWindowSize(m_sdl_window, &nTextureWidth, &nTextureHeight);
SDL_Rect m_image_rect, m_font_rect;
m_image_rect.x = 0;
m_image_rect.y = 0;
m_image_rect.w = nTextureWidth;
m_image_rect.h = nTextureHeight;
SDL_Rect m_src_rect, m_dst_rect, m_font_rect;
m_src_rect.x = 0;
m_src_rect.y = 0;
m_src_rect.w = v_frame->m_frame->width;
m_src_rect.h = v_frame->m_frame->height;
switch (_opt->aspect_type)
{
case keep_aspect_ratio: // 始终保持纵横比且图像居中
if (m_src_rect.w < _opt->width | m_src_rect.h < _opt->height)
{
m_dst_rect.x = (_opt->width - v_frame->m_frame->width)/2;
m_dst_rect.y = (_opt->height - v_frame->m_frame->height )/ 2;
m_dst_rect.w = v_frame->m_frame->width;
m_dst_rect.h = v_frame->m_frame->height;
}
else//否则按照帧大小播放
{
m_dst_rect.x = 0;
m_dst_rect.y = 0;
m_dst_rect.w = v_frame->m_frame->width;
m_dst_rect.h = v_frame->m_frame->height;
}
break;
case stretch_aspect_ratio://拉伸模式(画面会糊得妈都不认识)
m_dst_rect.x = 0;
m_dst_rect.y = 0;
m_dst_rect.w = v_frame->m_frame->width;
m_dst_rect.h = v_frame->m_frame->height;
break;
}
SDL_UpdateYUVTexture(m_sdl_texture,
&m_image_rect,
&m_src_rect,
v_frame->m_frame->data[0],
v_frame->m_frame->linesize[0],
v_frame->m_frame->data[1],
@ -96,13 +126,13 @@ void SDL2RenderWidget::update_image(MediaAVFrame* v_frame, v_sws_spec *v_spec)
v_frame->m_frame->data[2],
v_frame->m_frame->linesize[2]);
SDL_RenderClear(m_sdl_renderer);
SDL_RenderCopy(m_sdl_renderer, m_sdl_texture, &m_image_rect, NULL);
SDL_RenderCopy(m_sdl_renderer, m_sdl_texture, &m_src_rect, &m_dst_rect);
if (v_spec->info_state)
{
m_font_rect.x = 0;
m_font_rect.y = 0;
std::string info = "\n" + v_spec->filename + "\n" +
v_spec->width + "\n" +
v_spec->width + "\n" +
v_spec->height + "\n" +
v_spec->channels + "\n" +
v_spec->sample_rate + "\n" +
@ -140,20 +170,20 @@ void SDL2RenderWidget::renderer_text_info(SDL_Rect m_rect, std::string str, font
switch (f_type)
{
case media_info_str:
if(m_stb_media->fc.faceSize>20){
if (m_stb_media->fc.faceSize > 20)
{
m_stb_media->fc.clearGlyphs();
m_stb_media->setFontArgs(m_sdl_renderer, 20, 14);
}
m_stb_media->fc.drawText(m_rect.x, m_rect.y, str);
break;
case media_attachment:
break;
case default_logo_str:
m_stb_media->fc.drawText(m_rect.x, m_rect.y, str);
m_stb_media->fc.drawText(m_rect.x, m_rect.y, str);
break;
}
}
int SDL2RenderWidget::refresh_default_image(void *opaque)
{
@ -168,7 +198,7 @@ int SDL2RenderWidget::refresh_default_image(void *opaque)
QMetaObject::invokeMethod(
QApplication::instance(), [=]()
{ n_sdl->renderer_default_image(); },
Qt::QueuedConnection);
Qt::QueuedConnection);
}
SDL_Delay(n_sdl->sd_time);
}

4
SDL2RenderWidget.h

@ -30,7 +30,7 @@ class SDL2RenderWidget : public QWidget
public:
SDL2RenderWidget(QWidget *parent);
~SDL2RenderWidget();
void update_image(MediaAVFrame*,v_sws_spec*);
void update_image(MediaAVFrame*,v_sws_spec*,use_opt*);
void renderer_default_image();
void renderer_text_info(SDL_Rect m_rect,std::string str,font_renderer_type f_type);
void set_Size(QSize _size);
@ -51,6 +51,8 @@ private:
// 默认字符串
std::string logoImageStr = "F:/SourceCode/VTS/ZFFmpeg/ZFFmpeg/res/img/zvo.png";
std::string logoStr = "新时代社会主义中国";
signals:
void signals_change_size(int,int);
};
#endif

82
mediaplayer.cpp

@ -1,16 +1,23 @@
#include "MediaPlayer.h"
MediaPlayer::MediaPlayer() : m_avformat_ctx(nullptr),
m_video_avdecoder(new MediaAVDecoder),
m_audio_avdecoder(new MediaAVDecoder),
m_video_avdecoder(nullptr),
m_audio_avdecoder(nullptr),
m_render_receive_obj(nullptr),
m_sws_spec(new v_sws_spec)
m_sws_spec(nullptr),
m_sws_ctx(nullptr),
m_use_opt(nullptr),
m_video_af_frame(nullptr),
m_video_ot_frame(nullptr),
m_audio_af_frame(nullptr),
m_audio_ot_frame(nullptr)
{
m_sws_spec = new v_sws_spec;
m_use_opt = new use_opt;
m_sws_spec->info_state = true;
}
MediaPlayer::~MediaPlayer()
{
}
char *CharAVPixelFormat[]{
"AV_PIX_FMT_NONE",
@ -412,6 +419,7 @@ bool MediaPlayer::open_file(const char *filename)
return false;
}
// 查找视频解码器并打开解码器
m_video_avdecoder = new MediaAVDecoder;
if (!m_video_avdecoder->init(m_avformat_ctx, AVMEDIA_TYPE_VIDEO))
{
free_avformat_ctx();
@ -420,6 +428,8 @@ bool MediaPlayer::open_file(const char *filename)
}
else
{
m_use_opt->pix_fmt = AV_PIX_FMT_YUV420P;
m_use_opt->aspect_type = keep_aspect_ratio;
m_sws_ctx = sws_getContext(
m_video_avdecoder->m_avcodec_context->width,
m_video_avdecoder->m_avcodec_context->height,
@ -433,7 +443,9 @@ bool MediaPlayer::open_file(const char *filename)
NULL // param
);
}
// 查找音频解码器并打开解码器
m_audio_avdecoder = new MediaAVDecoder;
if (!m_audio_avdecoder->init(m_avformat_ctx, AVMEDIA_TYPE_AUDIO))
{
free_avformat_ctx();
@ -583,20 +595,20 @@ void MediaPlayer::demux_thread()
// printf("video packet queue size: %d, video frame queue size:%d, audio packet queue size:%d,audio frame queue size :%d\n",
// m_video_packet_queue.size(), m_video_frame_queue.size(), m_audio_packet_queue.size(), m_audio_frame_queue.size());
{
std::lock_guard <std::mutex>locker(m_pkt_video_queue_mutex);
if (m_video_frame_queue.size() > PACKETSIZE)
{
continue;
}
}
std::lock_guard<std::mutex> locker(m_pkt_video_queue_mutex);
if (m_video_frame_queue.size() > PACKETSIZE)
{
continue;
}
}
{
std::lock_guard <std::mutex>locker(m_pkt_audio_queue_mutex);
if (m_audio_frame_queue.size() > PACKETSIZE)
{
continue;
}
}
{
std::lock_guard<std::mutex> locker(m_pkt_audio_queue_mutex);
if (m_audio_frame_queue.size() > PACKETSIZE)
{
continue;
}
}
MediaAVPacket *packet = new MediaAVPacket;
int result = av_read_frame(m_avformat_ctx, packet->m_pakcet);
if (result < 0)
@ -652,7 +664,7 @@ void MediaPlayer::video_decode_thread()
m_video_packet_queue.pop_front();
video_decode(video_pkt);
delete video_pkt;
video_pkt=nullptr;
video_pkt = nullptr;
}
else
{
@ -670,7 +682,7 @@ void MediaPlayer::video_decode_thread()
video_pkt->m_pakcet->size = 0;
video_decode(video_pkt);
delete video_pkt;
video_pkt=nullptr;
video_pkt = nullptr;
break;
}
}
@ -713,7 +725,7 @@ void MediaPlayer::audio_decode_thread()
m_audio_packet_queue.pop_front();
audio_decode(audio_pkt);
delete audio_pkt;
audio_pkt=nullptr;
audio_pkt = nullptr;
}
else
{
@ -730,7 +742,7 @@ void MediaPlayer::audio_decode_thread()
audio_pkt->m_pakcet->size = 0;
audio_decode(audio_pkt);
delete audio_pkt;
audio_pkt=nullptr;
audio_pkt = nullptr;
printf("audio_decodec thread finished..................\n");
break;
}
@ -739,9 +751,8 @@ void MediaPlayer::audio_decode_thread()
}
void MediaPlayer::render_video_thread()
{
int frameSize = av_image_get_buffer_size(m_video_avdecoder->m_avcodec_context->pix_fmt, m_video_avdecoder->m_avcodec_context->width, m_video_avdecoder->m_avcodec_context->height, 1);
uint8_t *buffer = (uint8_t *)av_malloc(frameSize); // 指向YUV420的数据部分
m_frameSize = av_image_get_buffer_size(m_video_avdecoder->m_avcodec_context->pix_fmt, m_video_avdecoder->m_avcodec_context->width, m_video_avdecoder->m_avcodec_context->height, 1);
buffer = (uint8_t *)av_malloc(m_frameSize); // 指向YUV420的数据部分
static double m_previous_pts_diff = 40e-3;
static double m_previous_pts = 0;
static bool m_first_frame = true;
@ -855,7 +866,7 @@ void MediaPlayer::render_video_thread()
QMetaObject::invokeMethod(
QApplication::instance(), [=]()
{ m_render_receive_obj->update_image(m_video_ot_frame, m_sws_spec); },
{ m_render_receive_obj->update_image(m_video_ot_frame, m_sws_spec, m_use_opt); },
Qt::QueuedConnection);
}
av_free(buffer);
@ -883,6 +894,7 @@ void MediaPlayer::render_audio_thread()
locker.unlock();
m_audio_current_pts = m_audio_af_frame->m_frame->best_effort_timestamp * av_q2d(m_audio_avdecoder->m_avstream->time_base);
// the amount of time until we need to display this frame
double diff = m_audio_current_pts - m_previous_audio_pts;
if (m_first_frame)
@ -922,6 +934,11 @@ void MediaPlayer::render_audio_thread()
int32_t size = m_audio_af_frame->m_frame->nb_samples * bytes_per_sample * m_audio_af_frame->m_frame->channels;
char *data = av_pcm_clone(m_audio_af_frame->m_frame);
m_current_aduio_render_time = av_gettime();
// 音频时钟无效判断
if (m_current_aduio_render_time != AV_NOPTS_VALUE)
{
emit signals_play_time_changed(this);
}
SDL_QueueAudio(m_current_audio_deviceId, data, size);
free((void *)data);
}
@ -975,10 +992,11 @@ void MediaPlayer::get_video_size(int &width, int &height)
}
void MediaPlayer::set_video_size(int _width, int _height)
{
if (m_sws_spec && m_video_avdecoder)
if (m_use_opt)
{
m_sws_spec->width = _width;
m_sws_spec->height = _height;
pause_or_resume();
m_use_opt->width = _width;
m_use_opt->height = _height;
}
}
v_sws_spec *MediaPlayer::get_sws_specs()
@ -1005,3 +1023,11 @@ void MediaPlayer::register_render_windows_callback(SDL2RenderWidget *receiver)
{
m_render_receive_obj = receiver;
}
int MediaPlayer::get_duration()
{
return m_avformat_ctx ? round(m_avformat_ctx->duration * av_q2d(AV_TIME_BASE_Q)) : 0; // 时间转化为秒
}
int MediaPlayer::get_time()
{
return round(m_current_aduio_render_time);
}

49
mediaplayer.h

@ -37,16 +37,18 @@ class MediaPlayer:public QObject
public:
MediaPlayer();
~MediaPlayer();
bool start_play(const char *_filename);
bool stop_play();
void pause_resume_play();
void set_video_size(int _width,int _height);
void get_video_size(int &_width, int &_height);
void set_sws_specs(v_sws_spec*);
v_sws_spec* get_sws_specs();
v_state get_state();
AVFormatContext *get_fmt_ctx();
char *get_file_name();
bool start_play(const char *_filename);
bool stop_play();
void pause_resume_play();
void set_video_size(int _width,int _height);
void get_video_size(int &_width, int &_height);
void set_sws_specs(v_sws_spec*);
v_sws_spec* get_sws_specs();
v_state get_state();
AVFormatContext* get_fmt_ctx();
char* get_file_name();
int get_duration();
int get_time();
public:
void register_render_windows_callback(SDL2RenderWidget *receiver);
private:
@ -67,16 +69,17 @@ private:
private:
char* file_name;
AVFormatContext *m_avformat_ctx;
MediaAVDecoder *m_video_avdecoder;
MediaAVDecoder *m_audio_avdecoder;
SwsContext *m_sws_ctx=nullptr;
v_sws_spec *m_sws_spec=nullptr;
MediaAVFrame* m_video_af_frame=nullptr;
MediaAVFrame* m_video_ot_frame=nullptr;
MediaAVFrame* m_audio_af_frame=nullptr;
MediaAVFrame* m_audio_ot_frame=nullptr;
SDL2RenderWidget *m_render_receive_obj = nullptr;
AVFormatContext* m_avformat_ctx;
MediaAVDecoder* m_video_avdecoder;
MediaAVDecoder* m_audio_avdecoder;
SwsContext* m_sws_ctx;
v_sws_spec* m_sws_spec;
use_opt* m_use_opt;
MediaAVFrame* m_video_af_frame;
MediaAVFrame* m_video_ot_frame;
MediaAVFrame* m_audio_af_frame;
MediaAVFrame* m_audio_ot_frame;
SDL2RenderWidget *m_render_receive_obj;
SDL_AudioDeviceID m_current_audio_deviceId;
std::thread m_demux_thread;
@ -106,7 +109,9 @@ private:
bool m_demux_finish = false;
bool m_audio_decode_finish = false;
bool m_video_decode_finish = false;
int m_frameSize,n_frameSize;
uint8_t *buffer;
bool m_stop = false;
v_state m_status = v_state::none;
double m_theoretical_render_audio_time;
@ -114,5 +119,7 @@ private:
double m_current_aduio_render_time;
double m_previous_audio_pts = 0;
double m_audio_current_pts = 0;
signals:
void signals_play_time_changed(MediaPlayer*);
};
#endif

34
zffmpeg.cpp

@ -23,6 +23,7 @@ ZFFmpeg::ZFFmpeg(QWidget *parent)
btn_mutex_volumn(new QPushButton),
slider_volumn(new MediaSlider)
{
setMinimumSize(600, 400);
btn_play_reverse3s->setIcon(QIcon(tr(":/res/btn/reverse3s.png")));
btn_play_last->setIcon(QIcon(tr(":/res/btn/lastMedia.png")));
btn_play->setIcon(QIcon(tr(":/res/btn/play.png")));
@ -47,9 +48,9 @@ ZFFmpeg::ZFFmpeg(QWidget *parent)
layout_player_tool->addWidget(slider_volumn);
layout_player_tool->setSpacing(0);
label_current_time->setText(tr("00:00:00"));
label_current_time->setText(getTimeText(0));
label_n->setText(tr("/"));
label_duration_time->setText(tr("00:00:00"));
label_duration_time->setText(getTimeText(0));
slider_time->setOrientation(Qt::Orientation::Horizontal);
layout_player_state->addWidget(slider_time);
layout_player_state->addWidget(label_current_time);
@ -61,6 +62,7 @@ ZFFmpeg::ZFFmpeg(QWidget *parent)
widget_sdl2 = new SDL2RenderWidget(widget_player);
m_player = new MediaPlayer;
m_player->register_render_windows_callback(widget_sdl2);
m_player->set_video_size(size().width(),size().height());
layout_player->addWidget(widget_player);
layout_main->addLayout(layout_player);
@ -71,12 +73,15 @@ ZFFmpeg::ZFFmpeg(QWidget *parent)
layout_main->setStretch(2, 1);
layout_main->setSpacing(0);
setLayout(layout_main);
setMinimumSize(600, 400);
connect(btn_play, SIGNAL(clicked()), this, SLOT(play()));
connect(btn_play, SIGNAL(clicked()), this, SLOT(pause()));
connect(btn_stop, SIGNAL(clicked()), this, SLOT(stop()), Qt::QueuedConnection);
connect(btn_open_file, SIGNAL(clicked()), this, SLOT(set_open_file()));
connect(widget_sdl2, SIGNAL(signals_change_size(int,int)), this, SLOT(slots_change_size(int,int)));
connect(m_player, SIGNAL(signals_play_time_changed(MediaPlayer*)),this, SLOT(slots_play_time_changed(MediaPlayer*)));
connect(m_player, SIGNAL(signals_play_time_changed(MediaPlayer*)),this, SLOT(slots_on_time_slider_value_changed(MediaPlayer*)));
}
ZFFmpeg::~ZFFmpeg()
@ -99,17 +104,40 @@ void ZFFmpeg::keyReleaseEvent(QKeyEvent *event)
void ZFFmpeg::resizeEvent(QResizeEvent *event)
{
widget_sdl2->set_Size(size());
m_player->set_video_size(size().width(),size().height());
}
void ZFFmpeg::slots_change_size(int _w,int _h)
{
this->resize(_w,_h);
}
QString ZFFmpeg::getTimeText(int value) {
//获取XX:XX:XX格式的时间文本
QLatin1Char fill = QLatin1Char('0');
return QString("%1:%2:%3")
.arg(value/3600,2,10,fill)
.arg((value/60)%60,2,10,fill)
.arg(value%60,2,10,fill);
}
void ZFFmpeg::set_open_file()
{
ms_Path = QFileDialog::getOpenFileName(this, tr("选择要播放的文件"), tr(""));
play();
}
void ZFFmpeg::slots_play_time_changed(MediaPlayer* _player) {
slider_time->setValue(_player->get_time());
}
void ZFFmpeg::slots_on_time_slider_value_changed(MediaPlayer* _player) {
label_current_time->setText(getTimeText(_player->get_time()));
}
void ZFFmpeg::play()
{
if (ms_Path != nullptr)
{
m_player->start_play(ms_Path.toUtf8().data());
int duration = m_player->get_duration();
slider_time->setRange(0, duration);
label_duration_time->setText(getTimeText(duration));
}
}

5
zffmpeg.h

@ -68,10 +68,15 @@ private:
protected:
void keyReleaseEvent(QKeyEvent *event);
void resizeEvent(QResizeEvent *event);
private:
QString getTimeText(int value);
public slots:
void set_open_file();
void play();
void pause();
void stop();
void slots_change_size(int,int);
void slots_play_time_changed(MediaPlayer*);
void slots_on_time_slider_value_changed(MediaPlayer*);
};
#endif // ZFFMPEG_H

Loading…
Cancel
Save