tag v0.3.4
[rtmpclient.git] / app / src / main / jni / ai_suanzi_rtmpclient_Ffmpeg.cpp
1 //
2 // Created by Peng Li on 30/4/2018.
3 //
4 #include "ai_suanzi_rtmpclient_Ffmpeg.h"
5 #include <android/native_window.h>
6 #include <android/native_window_jni.h>
7 #include "log.h"
8 #include <stdlib.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <unistd.h>
13
14 extern "C" {
15     #include "libavformat/avformat.h"
16     #include "libavcodec/avcodec.h"
17     #include "libswscale/swscale.h"
18     #include "libavutil/imgutils.h"
19     #include "libavutil/time.h"
20     #include "libavdevice/avdevice.h"
21 }
22
23 int64_t start_time;
24 AVFormatContext *ofmt_ctx;
25 AVStream* video_st;
26 AVCodecContext* pCodecCtx;
27 AVCodec* pCodec;
28 AVPacket enc_pkt;
29 AVFrame *pFrameYUV;
30
31 void javaPrint(JNIEnv *env, jobject obj, const char* str)
32 {
33     jclass clazz = (*env).GetObjectClass(obj);
34     jobject mobj = env->NewGlobalRef(obj);
35     jmethodID mmid = env->GetMethodID(clazz, "print", "(Ljava/lang/String;)V");
36     jstring jstr = env->NewStringUTF(str);
37     env->CallVoidMethod(mobj, mmid, jstr);
38     env->DeleteLocalRef(jstr);
39 }
40
41 JNIEnv *g_env;
42 jobject g_obj;
43
44 void custom_log222 (void *ptr, int level, const char* fmt, va_list vl){
45     static int print_prefix = 1;
46     char line[1024];
47     av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
48     if (level <= AV_LOG_WARNING){
49         LOGE("%s", line);
50         javaPrint(g_env, g_obj, line);
51     } else {
52         //LOGE("%s", line);
53         //javaPrint(g_env, g_obj, line);
54     }
55 }
56
57 void custom_log(void *ptr, int level, const char* fmt, va_list vl){
58     //To TXT file
59     /*FILE *fp=fopen("/storage/emulated/0/av_log.txt","a+");
60     if(fp){
61     vfprintf(fp,fmt,vl);
62     fflush(fp);
63     fclose(fp);
64     }  */
65     //To Logcat
66     // LOGE(fmt, vl);
67     static int print_prefix = 1;
68     //static char prev[1024];
69     char line[1024];
70
71     av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
72
73     //strcpy(prev, line);
74     //sanitize((uint8_t *)line);
75
76     if (level <= AV_LOG_WARNING){
77         LOGE("%s", line);
78
79     } else {
80 //        LOGE("%s", line);
81     }
82 }
83
84
85 int framecnt = 0;
86 int yuv_width;
87 int yuv_height;
88 int y_length;
89 int uv_length;
90
91 JNIEXPORT void JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_init (JNIEnv *env, jobject obj ){
92     LOGE("########## Ffmpeg Init ##########");
93     unsigned int v = avutil_version();
94     LOGE("libavutil - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
95     v = avcodec_version();
96     LOGE("libavcodec - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
97     v = avformat_version();
98     LOGE("libavformat - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
99     v = avdevice_version();
100     LOGE("libavdevice - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
101
102     //system("su -c chmod 666 /dev/video0");
103     system("/system/xbin/su -c echo 'wowo' >> /data/local/test");
104     system("echo 'wowow' >> /sdcard/peng/test");
105
106     av_log_set_level(AV_LOG_TRACE);
107     av_register_all();
108     avdevice_register_all();
109     avformat_network_init();
110     av_log_set_callback(custom_log);
111 }
112
113
114 JNIEXPORT jstring JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_getVersion (JNIEnv *env, jobject obj) {
115     jint v = avformat_version();
116         LOGE("######### Ffmpeg JNI version i= %d", v);
117
118         system("su -c chmod 666 /dev/video0");
119
120     LOGE("######### Ffmpeg JNI version i= %d", v);
121
122
123     /*AVFormatContext *pFormatCtx = avformat_alloc_context();
124             avdevice_register_all();
125               av_log_set_callback(custom_log);
126         AVInputFormat *ifmt=av_find_input_format("video4linux2");
127         LOGE("===%s===", ifmt->name);
128         if(avformat_open_input(&pFormatCtx,"/dev/video0",ifmt,NULL)!=0){
129             LOGE("Couldn't open input stream.\n");
130                 return env->NewStringUTF("===== error =======");
131
132             //return -1;
133         }*/
134
135     return env->NewStringUTF("====== Ffmpeg call =======");
136 }
137
138 //const char* out_path;
139
140 JNIEXPORT void JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_setRtmpUrl (JNIEnv *env, jobject obj, jstring url){
141     LOGE("set rtmpurl");
142     //const char* out_path = "rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90_cameraid";
143     //out_path  = env->GetStringUTFChars(url, 0);
144 }
145
146
147
148 //#defind JLOGE(s) javaPrint(env, obj, (s));
149
150
151 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_initnew (JNIEnv *env, jobject obj, jint width, jint height, jstring url)
152 {
153     const char * out_path= env->GetStringUTFChars(url, 0);
154     LOGE("Ffmpeg init, width=%d, heigh=%d, url=%s", width, height, out_path);
155     javaPrint(env, obj, "Ffmpeg init");
156
157         yuv_width=width;
158         yuv_height=height;
159         y_length=width*height;
160         uv_length=width*height/4;
161
162
163         av_register_all();
164         avformat_network_init();
165         g_env = env;
166         g_obj = obj;
167         av_log_set_callback(custom_log222);
168
169
170         //output initialize
171         avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path);
172         //output encoder initialize
173         pCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
174         if (!pCodec){
175                 LOGE("Can not find encoder!\n");
176                 javaPrint(env, obj, "Can not find encoder!");
177                 return -1;
178         }
179         pCodecCtx = avcodec_alloc_context3(pCodec);
180         pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
181         pCodecCtx->width = width;
182         pCodecCtx->height = height;
183         pCodecCtx->time_base.num = 1;
184         pCodecCtx->time_base.den = 30;
185         pCodecCtx->bit_rate = 800000;
186         pCodecCtx->gop_size = 300;
187         /* Some formats want stream headers to be separate. */
188         if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
189                 pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
190
191         //H264 codec param
192         //pCodecCtx->me_range = 16;
193         //pCodecCtx->max_qdiff = 4;
194         //pCodecCtx->qcompress = 0.6;
195         pCodecCtx->qmin = 10;
196         pCodecCtx->qmax = 51;
197         //Optional Param
198         pCodecCtx->max_b_frames = 3;
199         // Set H264 preset and tune
200         AVDictionary *param = 0;
201         av_dict_set(&param, "preset", "ultrafast", 0);
202         av_dict_set(&param, "tune", "zerolatency", 0);
203
204         if (avcodec_open2(pCodecCtx, pCodec, &param) < 0){
205                 LOGE("Failed to open encoder!\n");
206                 javaPrint(env, obj, "Failed to open encoder!");
207                 return -1;
208         }
209
210         //Add a new stream to output,should be called by the user before avformat_write_header() for muxing
211         video_st = avformat_new_stream(ofmt_ctx, pCodec);
212         if (video_st == NULL){
213                 return -1;
214         }
215         video_st->time_base.num = 1;
216         video_st->time_base.den = 30;
217         video_st->codec = pCodecCtx;
218
219         //Open output URL,set before avformat_write_header() for muxing
220         jint ret = 0;
221         if (( ret = avio_open(&ofmt_ctx->pb, out_path, AVIO_FLAG_READ_WRITE)) < 0){
222                 LOGE("Failed to open output file! return :%s(%d)\n", av_err2str(ret),ret);
223                 javaPrint(env, obj, "Failed to open output file! return!");
224                 return -1;
225         }
226
227         //Write File Header
228         avformat_write_header(ofmt_ctx, NULL);
229
230         start_time = av_gettime();
231     env->ReleaseStringUTFChars(url, out_path);
232     return 0;
233
234 }
235
236 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_inithaha (JNIEnv *env, jobject obj, jint width, jint height) {
237
238         //const char* out_path = "/storage/emulated/0/Movies/output.flv";
239
240     //const char* out_path = "rtmp://192.168.1.35:1935/myapp/suanzi";
241     const char* out_path = "rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90_cameraid";
242
243     // const char* out_path = "/storage/sdcard0/output.flv";
244
245
246
247     LOGE("Ffmpeg init, width=%d, heigh=%d", width, height);
248
249         yuv_width=width;
250         yuv_height=height;
251         y_length=width*height;
252         uv_length=width*height/4;
253
254
255         av_register_all();
256
257         //output initialize
258         avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path);
259         //output encoder initialize
260         pCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
261         if (!pCodec){
262                 LOGE("Can not find encoder!\n");
263                 return -1;
264         }
265         pCodecCtx = avcodec_alloc_context3(pCodec);
266         pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
267         pCodecCtx->width = width;
268         pCodecCtx->height = height;
269         pCodecCtx->time_base.num = 1;
270         pCodecCtx->time_base.den = 30;
271         pCodecCtx->bit_rate = 800000;
272         pCodecCtx->gop_size = 300;
273         /* Some formats want stream headers to be separate. */
274         if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
275                 pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
276
277         //H264 codec param
278         //pCodecCtx->me_range = 16;
279         //pCodecCtx->max_qdiff = 4;
280         //pCodecCtx->qcompress = 0.6;
281         pCodecCtx->qmin = 10;
282         pCodecCtx->qmax = 51;
283         //Optional Param
284         pCodecCtx->max_b_frames = 3;
285         // Set H264 preset and tune
286         AVDictionary *param = 0;
287         av_dict_set(&param, "preset", "ultrafast", 0);
288         av_dict_set(&param, "tune", "zerolatency", 0);
289
290         if (avcodec_open2(pCodecCtx, pCodec, &param) < 0){
291                 LOGE("Failed to open encoder!\n");
292                 return -1;
293         }
294
295         //Add a new stream to output,should be called by the user before avformat_write_header() for muxing
296         video_st = avformat_new_stream(ofmt_ctx, pCodec);
297         if (video_st == NULL){
298                 return -1;
299         }
300         video_st->time_base.num = 1;
301         video_st->time_base.den = 30;
302         video_st->codec = pCodecCtx;
303
304         //Open output URL,set before avformat_write_header() for muxing
305         jint ret = 0;
306         if (( ret = avio_open(&ofmt_ctx->pb, out_path, AVIO_FLAG_READ_WRITE)) < 0){
307                 LOGE("Failed to open output file! return :%d\n", ret);
308                 return -1;
309         }
310
311         //Write File Header
312         avformat_write_header(ofmt_ctx, NULL);
313
314         start_time = av_gettime();
315     return 0;
316 }
317
318 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_flush (JNIEnv *env, jobject obj){
319         int ret;
320         int got_frame;
321         AVPacket enc_pkt;
322         if (!(ofmt_ctx->streams[0]->codec->codec->capabilities & CODEC_CAP_DELAY))
323                 return 0;
324         while (1) {
325                 enc_pkt.data = NULL;
326                 enc_pkt.size = 0;
327                 av_init_packet(&enc_pkt);
328                 ret = avcodec_encode_video2(ofmt_ctx->streams[0]->codec, &enc_pkt,
329                         NULL, &got_frame);
330                 if (ret < 0)
331                         break;
332                 if (!got_frame){
333                         ret = 0;
334                         break;
335                 }
336                 LOGE("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n", enc_pkt.size);
337
338                 //Write PTS
339                 AVRational time_base = ofmt_ctx->streams[0]->time_base;//{ 1, 1000 };
340                 AVRational r_framerate1 = { 60, 2 };
341                 AVRational time_base_q = { 1, AV_TIME_BASE };
342                 //Duration between 2 frames (us)
343                 int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));      //内部时间戳
344                 //Parameters
345                 enc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);
346                 enc_pkt.dts = enc_pkt.pts;
347                 enc_pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base);
348
349                 //转换PTS/DTS(Convert PTS/DTS)
350                 enc_pkt.pos = -1;
351                 framecnt++;
352                 ofmt_ctx->duration = enc_pkt.duration * framecnt;
353
354                 /* mux encoded frame */
355                 ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
356                 if (ret < 0)
357                         break;
358         }
359         //Write file trailer
360         av_write_trailer(ofmt_ctx);
361     return 0;
362 }
363
364 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_close (JNIEnv *env, jobject obj){
365         if (video_st)
366                 avcodec_close(video_st->codec);
367         avio_close(ofmt_ctx->pb);
368         avformat_free_context(ofmt_ctx);
369     return 0;
370 }
371
372
373
374 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_processnew (JNIEnv *env, jobject obj, jbyteArray yuv){
375
376 }
377
378
379
380 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_process (JNIEnv *env, jobject obj, jbyteArray yuv){
381         int ret;
382         int enc_got_frame=0;
383         int i=0;
384
385     //LOGE(" process data - ffmpeg");
386         pFrameYUV = av_frame_alloc();
387         uint8_t *out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
388         avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
389
390         //安卓摄像头数据为NV21格式,此处将其转换为YUV420P格式
391         jbyte* in= (jbyte*)env->GetByteArrayElements(yuv,0);
392         memcpy(pFrameYUV->data[0],in,y_length);
393         for(i=0;i<uv_length;i++)
394         {
395                 *(pFrameYUV->data[2]+i)=*(in+y_length+i*2);
396                 *(pFrameYUV->data[1]+i)=*(in+y_length+i*2+1);
397         }
398
399         pFrameYUV->format = AV_PIX_FMT_YUV420P;
400         pFrameYUV->width = yuv_width;
401         pFrameYUV->height = yuv_height;
402
403         enc_pkt.data = NULL;
404         enc_pkt.size = 0;
405         av_init_packet(&enc_pkt);
406         ret = avcodec_encode_video2(pCodecCtx, &enc_pkt, pFrameYUV, &enc_got_frame);
407         av_frame_free(&pFrameYUV);
408
409         if (enc_got_frame == 1){
410         if (framecnt % (15 * 60) == 0){
411                     LOGE("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, enc_pkt.size);
412                     javaPrint(env, obj, "Succeed to encode frame:");
413
414         }
415                 framecnt++;
416                 enc_pkt.stream_index = video_st->index;
417
418                 //Write PTS
419                 AVRational time_base = ofmt_ctx->streams[0]->time_base;//{ 1, 1000 };
420                 AVRational r_framerate1 = {60, 2 };//{ 50, 2 };
421                 AVRational time_base_q = { 1, AV_TIME_BASE };
422                 //Duration between 2 frames (us)
423                 int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));      //内部时间戳
424                 //Parameters
425                 //enc_pkt.pts = (double)(framecnt*calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));
426                 enc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);
427                 enc_pkt.dts = enc_pkt.pts;
428                 enc_pkt.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));
429                 enc_pkt.pos = -1;
430
431                 //Delay
432                 int64_t pts_time = av_rescale_q(enc_pkt.dts, time_base, time_base_q);
433                 int64_t now_time = av_gettime() - start_time;
434                 if (pts_time > now_time)
435                         av_usleep(pts_time - now_time);
436
437                 ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
438                 av_free_packet(&enc_pkt);
439         }
440     av_free(out_buffer);
441     return 0;
442 }
443
444 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_play (JNIEnv *env, jobject obj, jobject surface, jstring fname){
445
446
447
448
449
450     LOGE("###### video play #####");
451     // char * file_name = "/storage/emulated/0/Movies/big_buck_bunny_720p_10mb.mp4";
452     const char * file_name = env->GetStringUTFChars(fname, 0);
453
454     av_register_all();
455       avdevice_register_all();
456
457
458     AVFormatContext * pFormatCtx = avformat_alloc_context();
459
460
461 //////////
462               av_log_set_callback(custom_log);
463
464      AVInputFormat *ifmt=av_find_input_format("video4linux2");
465      LOGE("===%s===", ifmt->name);
466      if(avformat_open_input(&pFormatCtx,"/dev/video0",ifmt,NULL)!=0){
467              LOGE("Couldn't open file:\n");
468              return -1; // Couldn't open file
469      }
470
471
472 ///////////
473
474 /*
475     // Open video file
476     if(avformat_open_input(&pFormatCtx, file_name, NULL, NULL)!=0) {
477
478         LOGE("Couldn't open file:%s\n", file_name);
479         return -1; // Couldn't open file
480     }
481 */
482     // Retrieve stream information
483     if(avformat_find_stream_info(pFormatCtx, NULL)<0) {
484         LOGE("Couldn't find stream information.");
485         return -1;
486     }
487
488     // Find the first video stream
489     int videoStream = -1, i;
490     for (i = 0; i < pFormatCtx->nb_streams; i++) {
491         if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO
492            && videoStream < 0) {
493             videoStream = i;
494         }
495     }
496     if(videoStream==-1) {
497         LOGE("Didn't find a video stream.");
498         return -1; // Didn't find a video stream
499     }
500
501     // Get a pointer to the codec context for the video stream
502     AVCodecContext  * pCodecCtx = pFormatCtx->streams[videoStream]->codec;
503     LOGE("============= %d ========",__LINE__);
504     // Find the decoder for the video stream
505     AVCodec * pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
506     if(pCodec==NULL) {
507         LOGE("Codec not found.");
508         return -1; // Codec not found
509     }
510
511     if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
512         LOGE("Could not open codec.");
513         return -1; // Could not open codec
514     }
515
516     // 获取native window
517     ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
518
519     // 获取视频宽高
520     int videoWidth = pCodecCtx->width;
521     int videoHeight = pCodecCtx->height;
522
523     // 设置native window的buffer大小,可自动拉伸
524     ANativeWindow_setBuffersGeometry(nativeWindow,  videoWidth, videoHeight, WINDOW_FORMAT_RGBA_8888);
525     ANativeWindow_Buffer windowBuffer;
526
527     if(avcodec_open2(pCodecCtx, pCodec, NULL)<0) {
528         LOGE("Could not open codec.");
529         return -1; // Could not open codec
530     }
531
532     LOGE("stream format:%s", pFormatCtx->iformat->name);
533     LOGE("duration :%lld", (pFormatCtx->duration) / 1000000);
534     LOGE("Width, Height:%d x %d", pCodecCtx->width, pCodecCtx->height);
535     LOGE("Decoder name:%s", pCodec->name);
536
537     // Allocate video frame
538     AVFrame * pFrame = av_frame_alloc();
539
540     // 用于渲染
541     AVFrame * pFrameRGBA = av_frame_alloc();
542     if(pFrameRGBA == NULL || pFrame == NULL) {
543         LOGE("Could not allocate video frame.");
544         return -1;
545     }
546
547     // Determine required buffer size and allocate buffer
548     int numBytes=av_image_get_buffer_size(AV_PIX_FMT_RGBA, pCodecCtx->width, pCodecCtx->height, 1);
549     uint8_t * buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
550     av_image_fill_arrays(pFrameRGBA->data, pFrameRGBA->linesize, buffer, AV_PIX_FMT_RGBA,
551                          pCodecCtx->width, pCodecCtx->height, 1);
552
553     // 由于解码出来的帧格式不是RGBA的,在渲染之前需要进行格式转换
554     struct SwsContext *sws_ctx = sws_getContext(pCodecCtx->width,
555                              pCodecCtx->height,
556                              pCodecCtx->pix_fmt,
557                              pCodecCtx->width,
558                              pCodecCtx->height,
559                              AV_PIX_FMT_RGBA,
560                              SWS_BILINEAR,
561                              NULL,
562                              NULL,
563                              NULL);
564
565     int frameFinished;
566     AVPacket packet;
567     while(av_read_frame(pFormatCtx, &packet)>=0) {
568         // Is this a packet from the video stream?
569         if(packet.stream_index==videoStream) {
570
571             // Decode video frame
572             avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
573
574             // 并不是decode一次就可解码出一帧
575             if (frameFinished) {
576
577                 // lock native window buffer
578                 ANativeWindow_lock(nativeWindow, &windowBuffer, 0);
579
580                 // 格式转换
581                 sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
582                           pFrame->linesize, 0, pCodecCtx->height,
583                           pFrameRGBA->data, pFrameRGBA->linesize);
584
585                 // 获取stride
586                 uint8_t * dst = (uint8_t*) windowBuffer.bits;
587                 int dstStride = windowBuffer.stride * 4;
588                 uint8_t * src = (uint8_t*) (pFrameRGBA->data[0]);
589                 int srcStride = pFrameRGBA->linesize[0];
590
591                 // 由于window的stride和帧的stride不同,因此需要逐行复制
592                 int h;
593                 for (h = 0; h < videoHeight; h++) {
594                     memcpy(dst + h * dstStride, src + h * srcStride, srcStride);
595                 }
596
597                 ANativeWindow_unlockAndPost(nativeWindow);
598             }
599
600         }
601         av_packet_unref(&packet);
602     }
603
604     av_free(buffer);
605     av_free(pFrameRGBA);
606
607     // Free the YUV frame
608     av_free(pFrame);
609
610     // Close the codecs
611     avcodec_close(pCodecCtx);
612
613     // Close the video file
614     avformat_close_input(&pFormatCtx);
615
616      env->ReleaseStringUTFChars(fname, file_name);
617     return 0;
618 }
619
620 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_push (JNIEnv *env, jobject obj, jobject surface, jstring url){
621
622     /*
623     av_log_set_level(AV_LOG_TRACE);
624     av_register_all();
625     avformat_network_init();
626     avdevice_register_all();
627     */
628
629     LOGE("====push=====");
630 //    av_log_set_callback(custom_log);
631  // Open Output
632     //const char* out_path = "rtmp://192.168.1.35:1935/myapp/peng2";
633     const char* out_path =  "rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90_cameraid";
634     //const char* out_path =  env->GetStringUTFChars(url, 0);
635     //const char * file_name = env->GetStringUTFChars(fname, 0);
636
637
638     int ret = 0;
639     /// Open Input
640     AVFormatContext *pFormatCtx = avformat_alloc_context();
641
642     AVInputFormat *ifmt = av_find_input_format("video4linux2");
643     if((ret = avformat_open_input(&pFormatCtx, "/dev/video0", ifmt, NULL)) != 0) {
644     //    if((ret = avformat_open_input(&pFormatCtx, "/dev/bus/usb/003/007", ifmt, NULL)) != 0) {
645
646         LOGE("could not open file11, ret=%d, error=%s,", ret, av_err2str(ret));
647         return -1;
648     }
649
650     if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
651         LOGE( "could not find stream info");
652         return -1;
653     }
654
655     av_dump_format(pFormatCtx, 0, "0", 0);
656
657     AVCodec *dec;
658     int video_index = -1;
659     if((video_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0)) < 0){
660         LOGE( "error");
661         return -1;
662     }
663
664     AVCodecContext *pCodecCtx = pFormatCtx->streams[video_index]->codec;
665     if(avcodec_open2(pCodecCtx, dec, NULL) <0){
666         LOGE( "eee");
667         return -1;
668     }
669
670
671     // Open Output
672     //const char* out_path = "rtmp://192.168.1.35:1935/myapp/peng2";
673     //const char* out_path =  "rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90_cameraid";
674
675     AVFormatContext *ofmt_ctx;
676     avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path);
677     AVCodec *oDec = avcodec_find_encoder(AV_CODEC_ID_H264);
678     if (!oDec) {
679         LOGE("Can not find endoder");
680         return -1;
681     }
682
683     AVCodecContext *oCodecCtx = avcodec_alloc_context3(oDec);
684     oCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
685     oCodecCtx->width = pCodecCtx->width;
686     oCodecCtx->height = pCodecCtx->height;
687     oCodecCtx->time_base.num = 1;
688     oCodecCtx->time_base.den = 30;
689     oCodecCtx->bit_rate = 800000;
690     oCodecCtx->gop_size = 300;
691     if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
692         oCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
693     oCodecCtx->qmin = 10;
694     oCodecCtx->qmax = 51;
695     oCodecCtx->max_b_frames = 3;
696
697     AVDictionary *params = 0;
698     av_dict_set(&params, "preset", "ultrafast", 0);
699     av_dict_set(&params, "tune", "zerolatency", 0);
700
701     if (avcodec_open2(oCodecCtx, oDec, &params) < 0){
702         LOGE("Failed to open encoder");
703         return -1;
704     }
705
706     AVStream *videoStream = avformat_new_stream(ofmt_ctx, oDec);
707     if (videoStream == NULL){
708         return -1;
709     }
710
711     videoStream->time_base.num = 1;
712     videoStream->time_base.den = 30;
713     videoStream->codec = oCodecCtx;
714
715     if((ret = avio_open(&ofmt_ctx->pb, out_path, AVIO_FLAG_READ_WRITE)) < 0){
716         LOGE("Failed open out file22 erro=%d, ==%s==", ret, av_err2str(ret) );
717         //LOGE("Failed open out file22 erro=%d", ret);
718         return -1;
719     }
720
721     avformat_write_header(ofmt_ctx, NULL);
722     /////////////
723
724
725
726
727     //
728     AVFrame *pFrame, *pFrameYUV;
729     pFrame = av_frame_alloc();
730     pFrameYUV = av_frame_alloc();
731
732     int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
733     uint8_t *buffer = (uint8_t *)av_malloc(num_bytes * sizeof(uint8_t));
734     av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
735
736     pFrameYUV->format = AV_PIX_FMT_YUV420P;
737     pFrameYUV->width = pCodecCtx->width;
738     pFrameYUV->height = pCodecCtx->height;
739
740     struct SwsContext *img_convert_ctx;
741     img_convert_ctx = sws_getContext(pCodecCtx->width,
742                               pCodecCtx->height,
743                               pCodecCtx->pix_fmt,
744                               pCodecCtx->width,
745                               pCodecCtx->height,
746                               AV_PIX_FMT_YUV420P,
747                               SWS_BICUBIC,
748                               NULL, NULL, NULL);
749
750     AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
751     int got_picture = 0;
752
753     AVPacket enc_pkt ;
754
755     int64_t framecnt = 0;
756
757     while(av_read_frame(pFormatCtx, packet) >= 0){
758         if (packet->stream_index == video_index){
759             ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
760             if (ret < 0){
761                 LOGE("Decode Error.");
762                 return -1;
763             }
764             if (got_picture){
765                 sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
766
767                 enc_pkt.data = NULL;
768                 enc_pkt.size = 0;
769                 av_init_packet(&enc_pkt);
770                 int enc_got_frame = 0;
771                 ret = avcodec_encode_video2(oCodecCtx, &enc_pkt, pFrameYUV, &enc_got_frame);
772                 if (enc_got_frame == 1){
773
774                             framecnt++;
775                     enc_pkt.stream_index = videoStream->index;
776
777                     // write PTS
778                     AVRational time_base = ofmt_ctx->streams[0]->time_base;
779                     AVRational r_framerate1 = {60, 2};
780                     AVRational time_base_q = {1, AV_TIME_BASE};
781
782                             int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));  //内部时间戳
783                     enc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);
784                     enc_pkt.dts = enc_pkt.pts;
785                     enc_pkt.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));
786                     enc_pkt.pos = -1;
787
788                     int64_t pts_time = av_rescale_q(enc_pkt.dts, time_base, time_base_q);
789
790                 ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
791                 //av_frame_free(&pFrameYUV);
792                 //av_packet_unref(packet);
793
794                 av_free_packet(&enc_pkt);
795                 //av_packet_unref(&enc_pkt);
796                 }
797             }
798         }
799         av_packet_unref(packet);
800     }
801
802     sws_freeContext(img_convert_ctx);
803     av_free(pFrameYUV);
804     av_free(pFrame);
805     avcodec_close(pCodecCtx);
806     avformat_close_input(&pFormatCtx);
807     return 0;
808 }
809
810 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_preview (JNIEnv *env, jobject obj, jobject surface){
811
812     LOGE("###### video preview #####");
813
814     av_register_all();
815     avdevice_register_all();
816
817
818     AVFormatContext * pFormatCtx = avformat_alloc_context();
819
820
821     av_log_set_callback(custom_log);
822
823      AVInputFormat *ifmt=av_find_input_format("video4linux2");
824      LOGE("===%s===", ifmt->name);
825      if(avformat_open_input(&pFormatCtx,"/dev/video0",ifmt,NULL)!=0){
826              LOGE("Couldn't open file:\n");
827              return -1; // Couldn't open file
828      }
829
830     // Retrieve stream information
831     if(avformat_find_stream_info(pFormatCtx, NULL)<0) {
832         LOGE("Couldn't find stream information.");
833         return -1;
834     }
835
836     // Find the first video stream
837     int videoStream = -1, i;
838     for (i = 0; i < pFormatCtx->nb_streams; i++) {
839         if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO
840            && videoStream < 0) {
841             videoStream = i;
842         }
843     }
844     if(videoStream==-1) {
845         LOGE("Didn't find a video stream.");
846         return -1; // Didn't find a video stream
847     }
848
849     // Get a pointer to the codec context for the video stream
850     AVCodecContext  * pCodecCtx = pFormatCtx->streams[videoStream]->codec;
851     LOGE("============= %d ========",__LINE__);
852     // Find the decoder for the video stream
853     AVCodec * pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
854     if(pCodec==NULL) {
855         LOGE("Codec not found.");
856         return -1; // Codec not found
857     }
858
859     if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
860         LOGE("Could not open codec.");
861         return -1; // Could not open codec
862     }
863
864     // 获取native window
865     ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
866
867     // 获取视频宽高
868     int videoWidth = pCodecCtx->width;
869     int videoHeight = pCodecCtx->height;
870
871     // 设置native window的buffer大小,可自动拉伸
872     ANativeWindow_setBuffersGeometry(nativeWindow,  videoWidth, videoHeight, WINDOW_FORMAT_RGBA_8888);
873     ANativeWindow_Buffer windowBuffer;
874
875
876     LOGE("stream format:%s", pFormatCtx->iformat->name);
877     LOGE("duration :%lld", (pFormatCtx->duration) / 1000000);
878     LOGE("Width, Height:%d x %d", pCodecCtx->width, pCodecCtx->height);
879     LOGE("Decoder name:%s", pCodec->name);
880
881     // Allocate video frame
882     AVFrame * pFrame = av_frame_alloc();
883
884     // 用于渲染
885     AVFrame * pFrameRGBA = av_frame_alloc();
886     if(pFrameRGBA == NULL || pFrame == NULL) {
887         LOGE("Could not allocate video frame.");
888         return -1;
889     }
890
891     // Determine required buffer size and allocate buffer
892     int numBytes=av_image_get_buffer_size(AV_PIX_FMT_RGBA, pCodecCtx->width, pCodecCtx->height, 1);
893     uint8_t * buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
894     av_image_fill_arrays(pFrameRGBA->data, pFrameRGBA->linesize, buffer, AV_PIX_FMT_RGBA,
895                          pCodecCtx->width, pCodecCtx->height, 1);
896
897     // 由于解码出来的帧格式不是RGBA的,在渲染之前需要进行格式转换
898     struct SwsContext *sws_ctx = sws_getContext(pCodecCtx->width,
899                              pCodecCtx->height,
900                              pCodecCtx->pix_fmt,
901                              pCodecCtx->width,
902                              pCodecCtx->height,
903                              AV_PIX_FMT_RGBA,
904                              SWS_BILINEAR,
905                              NULL,
906                              NULL,
907                              NULL);
908
909     int frameFinished;
910     AVPacket packet;
911     while(av_read_frame(pFormatCtx, &packet)>=0) {
912         // Is this a packet from the video stream?
913         if(packet.stream_index==videoStream) {
914
915             // Decode video frame
916             avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
917
918             // 并不是decode一次就可解码出一帧
919             if (frameFinished) {
920
921                 // lock native window buffer
922                 ANativeWindow_lock(nativeWindow, &windowBuffer, 0);
923
924                 // 格式转换
925                 sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
926                           pFrame->linesize, 0, pCodecCtx->height,
927                           pFrameRGBA->data, pFrameRGBA->linesize);
928
929                 // 获取stride
930                 uint8_t * dst = (uint8_t*) windowBuffer.bits;
931                 int dstStride = windowBuffer.stride * 4;
932                 uint8_t * src = (uint8_t*) (pFrameRGBA->data[0]);
933                 int srcStride = pFrameRGBA->linesize[0];
934
935                 // 由于window的stride和帧的stride不同,因此需要逐行复制
936                 int h;
937                 for (h = 0; h < videoHeight; h++) {
938                     memcpy(dst + h * dstStride, src + h * srcStride, srcStride);
939                 }
940
941                 ANativeWindow_unlockAndPost(nativeWindow);
942             }
943
944         }
945         av_packet_unref(&packet);
946     }
947
948     av_free(buffer);
949     av_free(pFrameRGBA);
950
951     // Free the YUV frame
952     av_free(pFrame);
953
954     // Close the codecs
955     avcodec_close(pCodecCtx);
956
957     // Close the video file
958     avformat_close_input(&pFormatCtx);
959
960      //env->ReleaseStringUTFChars(fname, file_name);
961     return 0;
962 }
963
964 JNIEXPORT jstring JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_getPerfectDevice (JNIEnv *env, jobject obj) {
965     int ret;
966     LOGE("getPerfectDevice");
967     AVFormatContext *pFormatCtx = avformat_alloc_context();
968     AVInputFormat *ifmt = av_find_input_format("video4linux2");
969     if((ret = avformat_open_input(&pFormatCtx, "/dev/video0", ifmt, NULL)) != 0) {
970         LOGE("could not open file11, ret=%d, error=%s,", ret, av_err2str(ret));
971         //return ;
972     }
973     if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
974         LOGE( "could not find stream info");
975         //return -1;
976     }
977     av_dump_format(pFormatCtx, 0, "0", 0);
978     avformat_free_context(pFormatCtx);
979     //system("su -c \"find / -perm -2000 -o -perm -4000; ps; ls\"");
980     system("touch /storage/sdcard0/aa");
981
982     return env->NewStringUTF("====== Ffmpeg call =======");
983 }
984
985
986
987
988 JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_Ffmpeg_test (JNIEnv *env, jobject obj, jint fd){
989     char path[512] = {0};
990     char* real_path = NULL;
991
992     LOGE("=================");
993     //system("su -c chmod 666 /dev/video0");
994     /*
995 #ifdef ANDROID_USB_CAMERA
996     //MY_USB_CAMER_FD = fd;
997     avdevice_set_android_usb_fd(fd);
998
999     //LOGE("MY camer fd is %d", MY_USB_CAMER_FD);
1000 #endif
1001
1002     sprintf(path, "/proc/%d/fd/%d", getpid(), fd);
1003     if(path[0] != '\0'){
1004         LOGE("fd path is %s.", path);
1005         real_path = realpath(path, NULL);
1006         if(real_path != NULL){
1007             LOGE("get full path from fd %s.", real_path);
1008             free(real_path);
1009         }
1010     }
1011 */
1012
1013 /*
1014
1015
1016
1017     LOGE("====push=====");
1018 //    av_log_set_callback(custom_log);
1019
1020     int ret = 0;
1021     /// Open Input
1022     AVFormatContext *pFormatCtx = avformat_alloc_context();
1023
1024     AVInputFormat *ifmt = av_find_input_format("video4linux2");
1025     //if((ret = avformat_open_input(&pFormatCtx, "/dev/video0", ifmt, NULL)) != 0) {
1026         if((ret = avformat_open_input(&pFormatCtx, real_path, ifmt, NULL)) != 0) {
1027
1028         LOGE("could not open file11, ret=%d, error=%s,", ret, av_err2str(ret));
1029         return -1;
1030     }
1031
1032     if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
1033         LOGE( "could not find stream info");
1034         return -1;
1035     }
1036
1037     av_dump_format(pFormatCtx, 0, "0", 0);
1038
1039     AVCodec *dec;
1040     int video_index = -1;
1041     if((video_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0)) < 0){
1042         LOGE( "error");
1043         return -1;
1044     }
1045
1046     AVCodecContext *pCodecCtx = pFormatCtx->streams[video_index]->codec;
1047     if(avcodec_open2(pCodecCtx, dec, NULL) <0){
1048         LOGE( "eee");
1049         return -1;
1050     }
1051
1052
1053     // Open Output
1054     //const char* out_path = "rtmp://192.168.1.35:1935/myapp/peng2";
1055     const char* out_path =  "rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90_cameraid";
1056
1057     AVFormatContext *ofmt_ctx;
1058     avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path);
1059     AVCodec *oDec = avcodec_find_encoder(AV_CODEC_ID_H264);
1060     if (!oDec) {
1061         LOGE("Can not find endoder");
1062         return -1;
1063     }
1064
1065     AVCodecContext *oCodecCtx = avcodec_alloc_context3(oDec);
1066     oCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
1067     oCodecCtx->width = pCodecCtx->width;
1068     oCodecCtx->height = pCodecCtx->height;
1069     oCodecCtx->time_base.num = 1;
1070     oCodecCtx->time_base.den = 30;
1071     oCodecCtx->bit_rate = 800000;
1072     oCodecCtx->gop_size = 300;
1073     if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
1074         oCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
1075     oCodecCtx->qmin = 10;
1076     oCodecCtx->qmax = 51;
1077     oCodecCtx->max_b_frames = 3;
1078
1079     AVDictionary *params = 0;
1080     av_dict_set(&params, "preset", "ultrafast", 0);
1081     av_dict_set(&params, "tune", "zerolatency", 0);
1082
1083     if (avcodec_open2(oCodecCtx, oDec, &params) < 0){
1084         LOGE("Failed to open encoder");
1085         return -1;
1086     }
1087
1088     AVStream *videoStream = avformat_new_stream(ofmt_ctx, oDec);
1089     if (videoStream == NULL){
1090         return -1;
1091     }
1092
1093     videoStream->time_base.num = 1;
1094     videoStream->time_base.den = 30;
1095     videoStream->codec = oCodecCtx;
1096
1097     if((ret = avio_open(&ofmt_ctx->pb, out_path, AVIO_FLAG_READ_WRITE)) < 0){
1098         LOGE("Failed open out file22 erro=%d, ==%s==", ret, av_err2str(ret) );
1099         //LOGE("Failed open out file22 erro=%d", ret);
1100         return -1;
1101     }
1102
1103     avformat_write_header(ofmt_ctx, NULL);
1104     /////////////
1105
1106
1107
1108
1109     //
1110     AVFrame *pFrame, *pFrameYUV;
1111     pFrame = av_frame_alloc();
1112     pFrameYUV = av_frame_alloc();
1113
1114     int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
1115     uint8_t *buffer = (uint8_t *)av_malloc(num_bytes * sizeof(uint8_t));
1116     av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
1117
1118     pFrameYUV->format = AV_PIX_FMT_YUV420P;
1119     pFrameYUV->width = pCodecCtx->width;
1120     pFrameYUV->height = pCodecCtx->height;
1121
1122     struct SwsContext *img_convert_ctx;
1123     img_convert_ctx = sws_getContext(pCodecCtx->width,
1124                               pCodecCtx->height,
1125                               pCodecCtx->pix_fmt,
1126                               pCodecCtx->width,
1127                               pCodecCtx->height,
1128                               AV_PIX_FMT_YUV420P,
1129                               SWS_BICUBIC,
1130                               NULL, NULL, NULL);
1131
1132     AVPacket *packet = (AVPacket *)av_malloc(sizeof(AVPacket));
1133     int got_picture = 0;
1134
1135     AVPacket enc_pkt ;
1136
1137     int64_t framecnt = 0;
1138
1139     while(av_read_frame(pFormatCtx, packet) >= 0){
1140         if (packet->stream_index == video_index){
1141             ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
1142             if (ret < 0){
1143                 LOGE("Decode Error.");
1144                 return -1;
1145             }
1146             if (got_picture){
1147                 sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
1148
1149                 enc_pkt.data = NULL;
1150                 enc_pkt.size = 0;
1151                 av_init_packet(&enc_pkt);
1152                 int enc_got_frame = 0;
1153                 ret = avcodec_encode_video2(oCodecCtx, &enc_pkt, pFrameYUV, &enc_got_frame);
1154                 if (enc_got_frame == 1){
1155
1156                             framecnt++;
1157                     enc_pkt.stream_index = videoStream->index;
1158
1159                     // write PTS
1160                     AVRational time_base = ofmt_ctx->streams[0]->time_base;
1161                     AVRational r_framerate1 = {60, 2};
1162                     AVRational time_base_q = {1, AV_TIME_BASE};
1163
1164                             int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));  //内部时间戳
1165                     enc_pkt.pts = av_rescale_q(framecnt*calc_duration, time_base_q, time_base);
1166                     enc_pkt.dts = enc_pkt.pts;
1167                     enc_pkt.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));
1168                     enc_pkt.pos = -1;
1169
1170                     int64_t pts_time = av_rescale_q(enc_pkt.dts, time_base, time_base_q);
1171
1172                 ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
1173                 //av_frame_free(&pFrameYUV);
1174                 //av_packet_unref(packet);
1175
1176                 av_free_packet(&enc_pkt);
1177                 //av_packet_unref(&enc_pkt);
1178                 }
1179             }
1180         }
1181         av_packet_unref(packet);
1182     }
1183
1184     sws_freeContext(img_convert_ctx);
1185     av_free(pFrameYUV);
1186     av_free(pFrame);
1187     avcodec_close(pCodecCtx);
1188     avformat_close_input(&pFormatCtx);
1189
1190
1191 */
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203 }