-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathandzop-desktop.c
197 lines (175 loc) · 6.32 KB
/
andzop-desktop.c
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/**
this is the wrapper of the native functions that provided for AndZop
it also glues the decoders
single-thread version for simplicity
1. parse the video to retrieve video packets
2. takes a packet decode the video and put them into a picture/frame queue
gcc -o andzop andzop-desktop.c -lavcodec -lavformat -lavutil -lswscale -lz
current implementation only works for video without sound
**/
/*standard library*/
#include <time.h>
#include <math.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <assert.h>
/*ffmpeg headers*/
#include "libavutil/avstring.h"
//#include <libavutil/colorspace.h>
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/opt.h"
#include "libavcodec/avfft.h"
static int gsState; //gs=>global static
char *gFileName; //the file name of the video
AVFormatContext *gFormatCtx;
int gVideoStreamIndex;
AVPacket gVideoPacket;
/*structure for decoded video frame*/
typedef struct VideoPicture {
double pts;
double delay;
int width, height;
AVPicture data;
} VideoPicture;
VideoPicture gVideoPicture;
AVCodecContext *gVideoCodecCtx;
struct SwsContext *gImgConvertCtx;
#define LOGI(...) printf(__VA_ARGS__)
#define LOGE(...) printf(__VA_ARGS__)
static void parse_thread_function(void *arg);
static void decode_a_video_packet();
static void dump_frame_to_file();
static void closeVideo();
static void render_a_frame();
/*parsing the video file, done by parse thread*/
static void parse_thread_function(void *arg) {
AVCodec *lVideoCodec;
int lError;
/*some global variables initialization*/
LOGI("parse_thread_function starts!");
/*register the codec, demux, and protocol*/
//extern AVCodec ff_h263_decoder;
//avcodec_register(&ff_h263_decoder);
//extern AVInputFormat ff_mov_demuxer;
//av_register_input_format(&ff_mov_demuxer);
//extern URLProtocol ff_file_protocol;
//av_register_protocol2(&ff_file_protocol, sizeof(ff_file_protocol));
avcodec_register_all();
av_register_all();
/*open the video file*/
if ((lError = av_open_input_file(&gFormatCtx, gFileName, NULL, 0, NULL)) !=0 ) {
LOGI("Error open video file: %d", lError);
return; //open file failed
}
/*retrieve stream information*/
if ((lError = av_find_stream_info(gFormatCtx)) < 0) {
LOGI("Error find stream information: %d", lError);
return;
}
/*find the video stream and its decoder*/
gVideoStreamIndex = av_find_best_stream(gFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &lVideoCodec, 0);
if (gVideoStreamIndex == AVERROR_STREAM_NOT_FOUND) {
LOGI("Error: cannot find a video stream");
return;
}
if (gVideoStreamIndex == AVERROR_DECODER_NOT_FOUND) {
LOGI("Error: video stream found, but no decoder is found!");
return;
}
/*open the codec*/
gVideoCodecCtx = gFormatCtx->streams[gVideoStreamIndex]->codec;
if (avcodec_open(gVideoCodecCtx, lVideoCodec) < 0) {
LOGI("Error: cannot open the video codec!");
return;
}
}
static void decode_a_video_packet() {
AVFrame *lVideoFrame = avcodec_alloc_frame();
int lRet;
int lNumOfDecodedFrames;
/*read the next video packet*/
LOGI("decode_a_video_packet");
if (av_read_frame(gFormatCtx, &gVideoPacket) >= 0) {
if (gVideoPacket.stream_index == gVideoStreamIndex) {
//it's a video packet
LOGI("got a video packet, decode it");
avcodec_decode_video2(gVideoCodecCtx, lVideoFrame, &lNumOfDecodedFrames, &gVideoPacket);
if (lNumOfDecodedFrames) {
LOGI("video packet decoded, start conversion");
//allocate the memory space for a new VideoPicture
avpicture_alloc(&gVideoPicture.data, PIX_FMT_RGB565BE, gVideoCodecCtx->width, gVideoCodecCtx->height);
gVideoPicture.width = gVideoCodecCtx->width;
gVideoPicture.height = gVideoCodecCtx->height;
//convert the frame to RGB formati
LOGI("video picture data allocated, try to get a sws context");
gImgConvertCtx = sws_getCachedContext(gImgConvertCtx, gVideoPicture.width, gVideoPicture.height, gVideoCodecCtx->pix_fmt, gVideoPicture.width, gVideoPicture.height, PIX_FMT_RGB565BE, SWS_BICUBIC, NULL, NULL, NULL);
if (gImgConvertCtx == NULL) {
LOGI("Error initialize the video frame conversion context");
}
LOGI("got sws context, try to scale the video frame");
sws_scale(gImgConvertCtx, lVideoFrame->data, lVideoFrame->linesize, 0, gVideoCodecCtx->height, gVideoPicture.data.data, gVideoPicture.data.linesize);
LOGI("video packet conversion done, start free memory");
/*free the packet*/
av_free_packet(&gVideoPacket);
av_free(lVideoFrame);
}
} else {
//it's not a video packet
av_free_packet(&gVideoPacket);
av_free(lVideoFrame);
}
}
}
/*for debug*/
static void dump_frame_to_file() {
FILE *pFile;
char szFilename[32];
int y;
// Open file
sLOGI(szFilename, "/sdcard/frame.ppm");
pFile=fopen(szFilename, "wb");
if(pFile==NULL)
return;
// Write header
fLOGI(pFile, "P6\n%d %d\n255\n", gVideoPicture.width, gVideoPicture.height);
// Write pixel data
for(y=0; y<gVideoPicture.height; y++)
fwrite(gVideoPicture.data.data[0]+y*gVideoPicture.data.linesize[0], 1, gVideoPicture.width*2, pFile);
// Close file
fclose(pFile);
}
static void closeVideo() {
/*close the video codec*/
avcodec_close(gVideoCodecCtx);
/*close the video file*/
av_close_input_file(gFormatCtx);
}
/*fill in data for a bitmap*/
static void render_a_frame() {
//take a VideoPicture nd read the data into lPixels
decode_a_video_packet();
LOGI("start to fill in the bitmap pixels: h: %d, w: %d", gVideoPicture.height, gVideoPicture.width);
LOGI("line size: %d", gVideoPicture.data.linesize[0]);
dump_frame_to_file();
}
int main(int argc, char **argv) {
/*get the video file name*/
gFileName = "3.3gp";
if (gFileName == NULL) {
LOGI("Error: cannot get the video file name!");
return;
}
LOGI("video file name is %s", gFileName);
parse_thread_function(NULL);
//*parse_thread_function(NULL);
LOGI("initialization done");
render_a_frame();
}