AVSubtitle是FFmpeg中用于存储字幕信息的结构体,包括多个字段,例如字幕的开始和结束时间、字幕类型、语言、样式等。在使用Qt显示AVSubtitle时,可以根据不同的字幕类型和样式,选择不同的控件来展示。
以下是一个简单的例子,演示如何使用Qt展示AVSubtitle的文本信息:
#include <QtCore>
#include <QtGui>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsTextItem>
#include "ffmpeg.h"
int main(int argc, char *argv[])
{
av_register_all();
// 打开视频文件
AVFormatContext *pFormatCtx = NULL;
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) {
qDebug() << "打开视频文件失败!";
return -1;
}
// 查找流信息
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
qDebug() << "无法获取流信息!";
return -1;
}
int videoIndex = -1, subtitleIndex = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++) {
AVCodecParameters *codecpar = pFormatCtx->streams[i]->codecpar;
if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoIndex = i;
} else if (codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
subtitleIndex = i;
}
}
if (videoIndex < 0 || subtitleIndex < 0) {
qDebug() << "没有找到视频流或字幕流!";
return -1;
}
// 打开视频解码器
AVCodecParameters *codecpar = pFormatCtx->streams[videoIndex]->codecpar;
AVCodec *pCodec = avcodec_find_decoder(codecpar->codec_id);
if (pCodec == NULL) {
qDebug() << "无法找到视频解码器!";
return -1;
}
AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_parameters_to_context(pCodecCtx, codecpar) < 0) {
qDebug() << "无法设置编解码器参数!";
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
qDebug() << "无法打开视频解码器!";
return -1;
}
// 打开字幕解码器
codecpar = pFormatCtx->streams[subtitleIndex]->codecpar;
pCodec = avcodec_find_decoder(codecpar->codec_id);
if (pCodec == NULL) {
qDebug() << "无法找到字幕解码器!";
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_parameters_to_context(pCodecCtx, codecpar) < 0) {
qDebug() << "无法设置编解码器参数!";
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
qDebug() << "无法打开字幕解码器!";
return -1;
}
// 创建Qt视图和场景
QGraphicsView *view = new QGraphicsView;
view->show();
QGraphicsScene *scene = new QGraphicsScene;
view->setScene(scene);
// 循环读取帧
AVPacket packet;
av_init_packet(&packet);
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == videoIndex) {
// 解码视频帧
AVFrame *pFrame = av_frame_alloc();
int ret = avcodec_send_packet(pCodecCtx, &packet);
if (ret < 0) {
qDebug() << "解码视频帧失败!";
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(pCodecCtx, pFrame);
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
break;
} else if (ret < 0) {
qDebug() << "解码视频帧失败!";
break;
}
// 将解码后的视频帧转换为QImage并展示在Qt视图中
QImage image(pFrame->data[0], pFrame->width, pFrame->height, QImage::Format_RGB888);
QGraphicsPixmapItem *item = scene->addPixmap(QPixmap::fromImage(image));
item->setScale(1.0 * view->width() / pFrame->width);
item->setPos(0, 0);
QCoreApplication::processEvents();
}
av_frame_free(&pFrame);
} else if (packet.stream_index == subtitleIndex) {
// 解码字幕包
AVSubtitle subtitle;
int ret = avcodec_decode_subtitle2(pCodecCtx, &subtitle, NULL, &packet);
if (ret < 0) {
qDebug() << "解码字幕包失败!";
break;
}
// 根据字幕类型和样式,选择不同的控件来展示
if (subtitle.format == SUBTITLE_ASS || subtitle.format == SUBTITLE_SSA) {
// ASS/SSA格式字幕,使用QGraphicsTextItem显示
QGraphicsTextItem *item = new QGraphicsTextItem(QString::fromUtf8(subtitle.rects[0]->ass));
item->setPos(0, view->height() - 50);
scene->addItem(item);
} else {
// 其他格式字幕,使用QLabel显示
QLabel *label = new QLabel(view);
label->setText(QString::fromLatin1((const char *)subtitle.rects[0]->data, subtitle.rects[0]->size));
label->setAlignment(Qt::AlignCenter);
label->setStyleSheet("background-color:black;color:white;");
label->setGeometry(0, view->height() - 50, view->width(), 50);
label->show();
}
avsubtitle_free(&subtitle);
}
av_packet_unref(&packet);
}
// 释放资源
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
在上述例子中,我们分别使用QGraphicsTextItem和QLabel两种不同的控件来展示ASS/SSA格式和其他格式的字幕。当然,还可以根据具体需求选择其他控件或自定义控件来展示字幕。