-
Notifications
You must be signed in to change notification settings - Fork 77
/
FFMPEG0.cpp
154 lines (119 loc) · 3.62 KB
/
FFMPEG0.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
extern "C"
{
# include <libavcodec\avcodec.h>
# include <libavformat\avformat.h>
# include <libswscale\swscale.h>
}
# include <iostream>
# include <stdio.h>
using namespace std;
extern "C"
{
void saveFrame(AVFrame* pFrame, int width, int height, int iFrame)
{
FILE *pFile;
char szFilename[32];
int y;
// Open file
sprintf(szFilename, "frame%d.ppm", iFrame);
pFile = fopen(szFilename, "wb");
if (pFile == NULL)
return;
// Write header
fprintf(pFile, "P6\n%d %d\n255\n", width, height);
// Write pixel data
for (y = 0; y < height; y++)
fwrite(pFrame->data[0] + y*pFrame->linesize[0], 1, width * 3, pFile);
// Close file
fclose(pFile);
}
}
int main(int argv, char* argc[])
{
av_register_all(); // 注册支持的文件格式及对应的codec
char* filenName = "E:\\CCTV-Clip\\0912-2.mov";
// 打开audio文件
AVFormatContext* pFormatCtx = nullptr;
// 读取文件头,将格式相关信息存放在AVFormatContext结构体中
if (avformat_open_input(&pFormatCtx, filenName, nullptr, nullptr) != 0)
return -1; // 打开失败
// 检测文件的流信息
if (avformat_find_stream_info(pFormatCtx, nullptr) < 0)
return -1; // 没有检测到流信息 stream infomation
// 在控制台输出文件信息
av_dump_format(pFormatCtx, 0, filenName, 0);
//查找视频流 video stream
int videoStream = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
}
if (videoStream == -1)
return -1; // 没有找到视频流video stream
AVCodecContext* pCodecCtxOrg = nullptr;
AVCodecContext* pCodecCtx = nullptr;
AVCodec* pCodec = nullptr;
pCodecCtxOrg = pFormatCtx->streams[videoStream]->codec; // codec context
// 找到video stream的 decoder
pCodec = avcodec_find_decoder(pCodecCtxOrg->codec_id);
if (!pCodec)
{
cout << "Unsupported codec!" << endl;
return -1;
}
// 不直接使用从AVFormatContext得到的CodecContext,要复制一个
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_copy_context(pCodecCtx, pCodecCtxOrg) != 0)
{
cout << "Could not copy codec context!" << endl;
return -1;
}
// open codec
if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0)
return -1; // Could open codec
AVFrame* pFrame = nullptr;
AVFrame* pFrameRGB = nullptr;
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
// 使用的缓冲区的大小
int numBytes = 0;
uint8_t* buffer = nullptr;
numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture*)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
struct SwsContext* sws_ctx = nullptr;
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr);
AVPacket packet;
int i = 0;
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == videoStream)
{
int frameFinished = 0;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished)
{
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0,
pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
if (++i <= 5)
{
saveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
}
}
}
}
av_free_packet(&packet);
av_free(buffer);
av_frame_free(&pFrameRGB);
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);
avcodec_close(pCodecCtxOrg);
avformat_close_input(&pFormatCtx);
getchar();
return 0;
}