98 lines
3.6 KiB
C++
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(), 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;
|
|
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;
|
|
if(vi_idx == -1) {
|
|
err = "Didn't find a Video Stream";
|
|
goto free;
|
|
}
|
|
auto codecpar = fmt_ctx->streams[vi_idx]->codecpar;
|
|
if(codec_id!=nullptr) *codec_id = codecpar->codec_id;
|
|
qDebug()<<"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==nullptr) {
|
|
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, nullptr) < 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;
|
|
}
|