qt/LedOK/base/ffutil.cpp
2023-05-19 18:50:21 +08:00

98 lines
3.6 KiB
C++

#include "ffutil.h"
#include <QPainter>
#include <QDebug>
extern "C"{
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
static void imgCleanupHandler(void *info) {
delete [] (uchar*)info;
}
QString videoInfo(QByteArray url, QImage &img, int64_t *dur, AVCodecID *codec_id) {
AVFormatContext *fmt_ctx = avformat_alloc_context();
QString err;
{
if(avformat_open_input(&fmt_ctx, url.constData(), 0, 0) != 0) {
err = "Couldn't open input stream";
goto free;
}
if(avformat_find_stream_info(fmt_ctx, 0) < 0) {
err = "Couldn't find stream information";
goto free;
}
if(dur) *dur = fmt_ctx->duration;
int vi_idx = -1;
for(uint ss=0; ss<fmt_ctx->nb_streams; ss++) if(fmt_ctx->streams[ss]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {vi_idx = ss; break;}
if(vi_idx == -1) {
err = "Didn't find a Video Stream";
goto free;
}
auto codecpar = fmt_ctx->streams[vi_idx]->codecpar;
if(codec_id) *codec_id = codecpar->codec_id;
qDebug()<<"codecpar w h"<<codecpar->width<<"x"<<codecpar->height<<"codec_id"<<codecpar->codec_id<<avcodec_get_name(codecpar->codec_id);
if(av_seek_frame(fmt_ctx, -1, 1000000, AVSEEK_FLAG_BACKWARD) < 0) {
err = "av_seek_frame fail";
goto free;
}
const AVCodec *decoder = avcodec_find_decoder(codecpar->codec_id);
if(decoder==0) {
err = "Could not found Video Decoder";
goto free;
}
auto vcCtx = avcodec_alloc_context3(decoder);
avcodec_parameters_to_context(vcCtx, codecpar);
if(avcodec_open2(vcCtx, decoder, 0) < 0) {
err = "Could not open Video Codec Ctx";
avcodec_free_context(&vcCtx);
goto free;
}
auto sws_ctx = sws_getContext(vcCtx->width, vcCtx->height, vcCtx->pix_fmt, vcCtx->width, vcCtx->height, AV_PIX_FMT_RGB32, SWS_FAST_BILINEAR, 0, 0, 0);
auto packet = av_packet_alloc();
auto frm = av_frame_alloc();
int dstStride[4]{(vcCtx->width*4+63)/64*64};
dstStride[3] = dstStride[0] * vcCtx->height;
uint8_t *dst[4]{0};
while(1) {
if(av_read_frame(fmt_ctx, packet) < 0) break;
if(packet->stream_index != vi_idx) continue;
int res = avcodec_send_packet(vcCtx, packet);
if(res < 0) break;
while((res = avcodec_receive_frame(vcCtx, frm)) != AVERROR(EAGAIN)) {
if(res < 0) goto free2;
dst[0] = new uchar[dstStride[3]];
sws_scale(sws_ctx, frm->data, frm->linesize, 0, vcCtx->height, dst, dstStride);
img = QImage(dst[0], vcCtx->width, vcCtx->height, dstStride[0], QImage::Format_ARGB32, imgCleanupHandler, dst[0]);
goto free2;
}
}
free2:
av_frame_free(&frm);
av_packet_free(&packet);
avcodec_free_context(&vcCtx);
sws_freeContext(sws_ctx);
}
free:
avformat_close_input(&fmt_ctx);
return err;
}
QString audioInfo(QByteArray url, int64_t *dur) {
AVFormatContext *fmt_ctx = avformat_alloc_context();
QString err;
{
if(avformat_open_input(&fmt_ctx, url.constData(), nullptr, nullptr) != 0) {
err = "Couldn't open input stream";
goto free;
}
if(avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
err = "Couldn't find stream information";
goto free;
}
if(dur!=nullptr) *dur = fmt_ctx->duration;
}
free:
avformat_close_input(&fmt_ctx);
return err;
}