代码如下:
function Video2Bmp(const strVideoFileName, strSavePath: string): Boolean;
var
pfc1 : PAVFormatContext;
pfc2 : PAVFormatContext;
intVideoStreamIndex: Integer;
pps : PPAVStream;
III : Integer;
pcc : PAVCodecContext;
pCodec : PAVCodec;
pFrameVdo : PAVFrame;
pFrameRGB : PAVFrame;
psc : PSwsContext;
avp : TAVPacket;
intRemain : Integer;
bFirst : Boolean;
intDecoded : Integer;
intFrameFinished : Integer;
bmp : TBitmap;
label
lbexit;
begin
Result := False;
{ 1. 注册所有容器格式和CODEC }
av_register_all();
{ 2. 打开文件 }
pfc1 := nil;
if avformat_open_input(pfc1, PAnsiChar(AnsiString(strVideoFileName)), nil, nil) <> 0 then
begin
ShowMessage('打开文件失败,请检查你的文件!');
Exit;
end;
{ 3. 从文件中提取流信息 }
if avformat_find_stream_info(pfc1, nil) < 0 then
begin
ShowMessage('不存在任何音频或视频流!');
Exit;
end;
{ 4. 穷举所有的流,查找是否包含视频流 }
intVideoStreamIndex := -1;
pfc2 := pfc1;
pps := pfc1^.streams;
for III := 0 to pfc1^.nb_streams - 1 do
begin
if pps^.codec.codec_type = AVMEDIA_TYPE_VIDEO then
begin
intVideoStreamIndex := III;
end;
inc(pps);
end;
if intVideoStreamIndex = -1 then
begin
ShowMessage('不存在视频流!');
Exit;
end;
{ 5. 定位到视频流 }
inc(pfc1^.streams, intVideoStreamIndex);
pcc := pfc1^.streams^.codec;
pCodec := avcodec_find_decoder(pcc^.codec_id);
if pCodec = nil then
begin
ShowMessage('找不到视频流!');
Exit;
end;
{ 6. 修正视频流 }
if (pCodec^.capabilities and CODEC_CAP_TRUNCATED) = CODEC_CAP_TRUNCATED then
pcc^.flags := pcc.flags or CODEC_FLAG_TRUNCATED;
if avcodec_open2(pcc, pCodec, nil) < 0 then
begin
ShowMessage('打开视频流发生错误!');
Exit;
end;
{ 7. 视频流转化为BMP }
if (pcc^.time_base.num > 1000) and (pcc^.time_base.den = 1) then
pcc^.time_base.den := 1000;
pFrameVdo := avcodec_alloc_frame();
pFrameRGB := avcodec_alloc_frame;
{ 按视频帧的原始大小输出图片 }
avpicture_alloc(PAVPicture(pFrameRGB), AV_PIX_FMT_RGB32, pcc^.Width, pcc^.Height);
psc := sws_getContext(pcc^.Width, pcc^.Height, pcc^.pix_fmt, pcc^.Width, pcc^.Height, AV_PIX_FMT_RGB32, SWS_BICUBIC, nil, nil, nil);
intRemain := 0;
bFirst := True;
{ 查找视频的每一帧 }
while True do
begin
if bFirst then
begin
bFirst := False;
avp.data := nil;
end;
while True do
begin
while intRemain > 0 do
begin
intDecoded := avcodec_decode_video2(pcc, pFrameVdo, intFrameFinished, @avp);
if intDecoded < 0 then
break;
dec(intRemain, intDecoded);
{ 找到完整的一帧 }
if intFrameFinished <> 0 then
begin
{ 按原图输出 }
sws_scale(psc, @pFrameVdo^.data, @pFrameVdo^.linesize, 0, pcc^.Height, @pFrameRGB^.data, @pFrameRGB^.linesize);
{ 输出位图 }
bmp := TBitmap.Create;
try
bmp.PixelFormat := pf32bit;
bmp.Width := pcc^.Width;
bmp.Height := pcc^.Height;
for III := 0 to bmp.Height - 1 do
begin
CopyMemory(bmp.ScanLine[III], Pointer(Integer(pFrameRGB.data[0]) + bmp.Width * 4 * III), bmp.Width * 4);
end;
bmp.SaveToFile(Format('%s\%d.bmp', [strSavePath, GetTickCount]));
finally
bmp.free;
end;
{ 寻找下一帧 }
Continue;
end;
end;
repeat
if av_read_frame(pfc2, @avp) < 0 then
goto lbexit;
until avp.stream_index = intVideoStreamIndex;
intRemain := avp.size;
end;
lbexit:
avcodec_decode_video2(pcc, pFrameVdo, intFrameFinished, @avp);
if avp.data <> nil then
av_free_packet(@avp);
if intFrameFinished = 0 then
break;
end;
{ 8. 释放资源 }
sws_freeContext(psc);
avpicture_free(PAVPicture(pFrameRGB));
av_free(pFrameRGB);
av_free(pFrameVdo);
avcodec_close(pcc);
avformat_close_input(pfc1);
{ 9. 返回成功 }
Result := True;
end;