279341b346966156cbd9e4c8dd28c046a8103428
[rtmpclient.git] / app / src / main / jni / FfmpegHelper.cpp
1 #include "FfmpegHelper.h"
2 #include "log.h"
3 #include <string>
4
5 #define FLOGE(...) av_log(NULL, AV_LOG_ERROR, __VA_ARGS__)
6 #define FLOGD(...) av_log(NULL, AV_LOG_DEBUG, __VA_ARGS__)
7
8 FfmpegHelper* FfmpegHelper::singleton = NULL;
9 bool FfmpegHelper::isInit = false;
10
11
12 FfmpegHelper::FfmpegHelper(JavaVM *vm, jclass cls)
13 : jvm(vm)
14 , ai_suanzi_rtmpclient_FfmpegHelper(cls)
15 {
16 }
17
18
19 jint FfmpegHelper::nativeOnLoad(JavaVM * vm, void* reserved)
20 {
21     JNIEnv* env;
22     if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
23         return -1;
24     }
25
26     jclass local_ref = 0;
27     if (env) local_ref = env->FindClass ("ai/suanzi/rtmpclient/FfmpegHelper");
28     jclass global_ref = reinterpret_cast<jclass> (env->NewGlobalRef (local_ref));
29     singleton = new FfmpegHelper(vm, global_ref);
30     return JNI_VERSION_1_6;
31 }
32
33 void FfmpegHelper::av_log_cb (void *ptr, int level, const char* fmt, va_list vl)
34
35     static int print_prefix = 1;
36     char line[1024];
37     av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
38
39     if (level <= AV_LOG_WARNING){
40         if (singleton) singleton->javaPrint(line);
41     } else {
42         if (singleton) singleton->javaPrint(line);
43         //LOGE("%s", line);
44     }
45 }
46
47 void FfmpegHelper::javaPrint(const char* str)
48 {
49     JNIEnv* env = 0;
50     if(this->jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
51         return;
52     }
53     jmethodID mid = env->GetStaticMethodID(ai_suanzi_rtmpclient_FfmpegHelper, "javaPrint", "(Ljava/lang/String;)V");
54     jstring jstr = env->NewStringUTF(str);
55     env->CallStaticVoidMethod(ai_suanzi_rtmpclient_FfmpegHelper, mid, jstr);
56     env->DeleteLocalRef(jstr);
57 }
58
59 void FfmpegHelper::init()
60 {    
61     av_log_set_callback(av_log_cb);
62     av_log_set_level(AV_LOG_DEBUG);
63     FLOGE("########## Ffmpeg Init ##########");
64     unsigned int v = avutil_version();
65     FLOGE("libavutil - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
66     v = avcodec_version();
67     FLOGE("libavcodec - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
68     v = avformat_version();
69     FLOGE("libavformat - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
70     v = avdevice_version();
71     FLOGE("libavdevice - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
72
73     av_register_all();
74     //avdevice_register_all();
75     int ret = 0;
76     if((ret = avformat_network_init()) != 0){
77         FLOGE("avformat_network_init, error:%s(%d)", av_err2str(ret), ret);
78     }
79     isInit = true;
80 }
81
82 int FfmpegHelper::initEncoder(int width, int height, const char* outpath)
83 {
84     if(!isInit) init();
85     FLOGE("initEncoder - width=%d, height=%d, url=%s", width, height, outpath);
86
87     pWidth = width;
88     pHeight = height;
89     int ret = 0;
90
91         avformat_alloc_output_context2(&formatCtx, NULL, "flv", outpath);
92
93     // initial encoder
94         if((codec = avcodec_find_encoder(AV_CODEC_ID_H264)) == NULL){
95                 FLOGE("Can not find encoder!\n");
96                 return -1;
97         }
98         codecCtx = avcodec_alloc_context3(codec);
99         codecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
100         codecCtx->width = width;
101         codecCtx->height = height;
102         codecCtx->time_base.num = 1;
103         codecCtx->time_base.den = 30;
104         codecCtx->bit_rate = 800000;
105         codecCtx->gop_size = 300;
106         if (formatCtx->oformat->flags & AVFMT_GLOBALHEADER) /* Some formats want stream headers to be separate. */
107                 codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
108         //H264 codec param
109         //pCodecCtx->me_range = 16;
110         //pCodecCtx->max_qdiff = 4;
111         //pCodecCtx->qcompress = 0.6;
112         codecCtx->qmin = 10;
113         codecCtx->qmax = 51;
114         //Optional Param
115         codecCtx->max_b_frames = 3;
116         // Set H264 preset and tune
117         AVDictionary *param = 0;
118         av_dict_set(&param, "preset", "ultrafast", 0);
119         av_dict_set(&param, "tune", "zerolatency", 0);
120         if ((ret = avcodec_open2(codecCtx, codec, &param)) < 0){
121                 LOGE("Failed to open encoder!, error:%s(%d)\n", av_err2str(ret), ret);
122                 return -1;
123         }
124
125         //Add a new stream to output,should be called by the user before avformat_write_header() for muxing
126         AVStream* vStream;
127     if ((vStream = avformat_new_stream(formatCtx, codec)) == NULL){
128         FLOGE("avformat_new_stream - error");
129         return -1;
130     }
131         vStream->time_base.num = 1;
132         vStream->time_base.den = 30;
133         vStream->codec = codecCtx;
134
135         //Open output URL,set before avformat_write_header() for muxing
136         if (( ret = avio_open(&formatCtx->pb, outpath, AVIO_FLAG_READ_WRITE)) < 0){
137                 LOGE("Failed to open output file! error :%s(%d)\n", av_err2str(ret), ret);
138                 return -1;
139         }
140
141         if((ret = avformat_write_header(formatCtx, NULL)) != 0){ //Write File Header
142                 LOGE("avformat_write_header error :%s(%d)\n", av_err2str(ret), ret);
143         return -1;
144     }
145     startTime = av_gettime();
146     return 0;
147 }
148
149 int FfmpegHelper::processFrame(uint8_t* data)
150 {
151     int ret = 0;
152     AVFrame *pFrame, *pFrameYUV;
153     pFrameYUV = av_frame_alloc();
154     int y_length = pWidth * pHeight;
155     uint8_t *outBuf = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, codecCtx->width, codecCtx->height, 1));
156     av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, outBuf, AV_PIX_FMT_YUV420P, codecCtx->width, codecCtx->height, 1);
157
158         memcpy(pFrameYUV->data[0], data, y_length);
159     for (int i = 0; i < y_length / 4; i++){
160         *(pFrameYUV->data[2] + i) = *(data + y_length * 2);
161         *(pFrameYUV->data[1] + i) = *(data + y_length * 2 + 1);
162     }
163
164         pFrameYUV->format = AV_PIX_FMT_YUV420P;
165         pFrameYUV->width = pWidth; 
166         pFrameYUV->height = pHeight;
167
168
169     AVPacket encPkt;
170     encPkt.data = NULL;
171     encPkt.size = 0;
172     av_init_packet(&encPkt);
173     int got_frame = 0;
174
175         avcodec_encode_video2(codecCtx, &encPkt, pFrameYUV, &got_frame);
176     av_frame_free(&pFrameYUV);
177
178     if(got_frame == 1){
179         if (frameCnt % (15 * 60) == 0){
180                     FLOGE("Succeed to encode frame: %5d\tsize:%5d\n", frameCnt, encPkt.size);
181         }
182         frameCnt++;
183                 encPkt.stream_index = vStream->index;
184
185         // PTS
186                 AVRational time_base = formatCtx->streams[0]->time_base;//{ 1, 1000 };
187                 AVRational r_framerate = {60, 2 };//{ 50, 2 };
188                 AVRational time_base_q = { 1, AV_TIME_BASE };
189                 //Duration between 2 frames (us)
190                 int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate));       //内部时间戳
191                 //Parameters
192                 //enc_pkt.pts = (double)(framecnt*calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));
193                 encPkt.pts = av_rescale_q(frameCnt*calc_duration, time_base_q, time_base);
194                 encPkt.dts = encPkt.pts;
195                 encPkt.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));
196                 encPkt.pos = -1;
197
198                 //Delay
199                 int64_t pts_time = av_rescale_q(encPkt.dts, time_base, time_base_q);
200                 int64_t now_time = av_gettime() - startTime;
201                 if (pts_time > now_time)
202                         av_usleep(pts_time - now_time);
203
204                 ret = av_interleaved_write_frame(formatCtx, &encPkt);
205                 av_packet_unref(&encPkt);
206     }
207     av_free(outBuf);
208     return 0;
209 }
210
211 int FfmpegHelper::close()
212 {
213     if(vStream)
214         avcodec_close(vStream->codec);
215     avio_close(formatCtx->pb);
216     avformat_free_context(formatCtx);
217     return 0;
218 }
219
220
221 jint FfmpegHelper::nativeInitialEncoder(JNIEnv *env, jclass cls, jint width, jint height, jstring url)
222 {
223     const char* output = env->GetStringUTFChars(url, 0);
224     int ret = 0;
225     if (singleton)  ret = singleton->initEncoder(width, height, output);
226     env->ReleaseStringUTFChars(url, output);
227     return ret;
228 }
229
230 jint FfmpegHelper::nativeProcessFrame(JNIEnv *env, jclass cls, jbyteArray data)
231 {
232         jbyte* buf = (jbyte*)env->GetByteArrayElements(data, 0);
233     int ret = 0;
234     if(singleton)  ret = singleton->processFrame((uint8_t *)buf);
235     return ret;
236 }
237
238 jint FfmpegHelper::nativeClose()
239 {
240     if(singleton) return singleton->close();
241     return 0;
242 }