ffmpeg实现mjpeg摄像头的采集-预览-拍照
摄像头输出是mjpeg格式的,需要实现在线预览功能,然后实现拍照功能
1.可以设置采集图像的分辨率,预览分辨率为640*480,可以自定义
2.ctrl+\ 拍照,ctrl+c 退出
void test() { if (signal(SIGQUIT, sigHandle) == SIG_ERR) { perror("set signal err"); } if (signal(SIGINT, sigHandle) == SIG_ERR) { perror("set signal err"); } AVOutputFormat *ofmt = NULL; AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL; AVCodecContext *ifcodec_ctx, *ofcodec_ctx; AVCodec *icodec, *ocodec; AVStream *out_stream; AVFrame *pFrame, *pFrameYUV420, *pFrameBGR; struct SwsContext *in_conCtx, *out_conCtx; unsigned char *in_buffer, *out_buffer; AVPacket inpkg, outpkg; const char *in_filename; int ret, i; int got_picture; IplImage *image; int videoindex = -1; int frame_index = 0; int64_t start_time = 0, end_time = 0; // in_filename = "test.mp4"; in_filename = "/dev/video1"; // in_filename = "rtmp://219.216.87.170/live/test3"; // out_filename = "rtmp://219.216.87.170/live/test2"; av_register_all(); avdevice_register_all(); avformat_network_init(); ifmt_ctx = avformat_alloc_context(); ifmt_ctx->probesize = 20000000; ifmt_ctx->max_analyze_duration = 2000; AVDictionary* options = NULL; av_dict_set(&options, "fflags", "nobuffer", 0); av_dict_set(&options, "max_delay", "100000", 0); av_dict_set(&options, "framerate", "30", 0); av_dict_set(&options, "input_format", "mjpeg", 0); av_dict_set(&options, "video_size", "1920x1080", 0); // av_dict_set(&options, "video_size", "1280x720", 0); if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, &options)) < 0) { printf("open input file err\n"); goto end; } av_dict_free(&options); if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) { printf("failed to retrieve input stream information\n"); goto end; } for (i = 0; i < ifmt_ctx->nb_streams; i++) { if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoindex = i; break; } printf("codec %d:%d %d\n", i, ifmt_ctx->streams[i]->codec->codec_type, ifmt_ctx->streams[i]->codec->codec_id); } // exit(1); ifcodec_ctx = ifmt_ctx->streams[videoindex]->codec; icodec = avcodec_find_decoder(ifcodec_ctx->codec_id); if (icodec == NULL) { printf("icodec not find\n"); goto end; } if (avcodec_open2(ifcodec_ctx, icodec, NULL) < 0) { printf("open icodec err\n"); goto end; } printf("**************** input file info ******************\n"); av_dump_format(ifmt_ctx, 0, in_filename, 0); // avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_filename); ofmt_ctx = avformat_alloc_context(); if (!ofmt_ctx) { printf("could not create output context\n"); ret = AVERROR_UNKNOWN; goto end; } ofmt = av_guess_format("mjpeg", NULL, NULL); ofmt_ctx->oformat = ofmt; out_stream = avformat_new_stream(ofmt_ctx, NULL); if (!out_stream) { printf("failed allocating output stream\n"); ret = AVERROR_UNKNOWN; goto end; } ofcodec_ctx = out_stream->codec; ofcodec_ctx->codec_id = ofmt->video_codec; ofcodec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; ofcodec_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P; ofcodec_ctx->width = ifcodec_ctx->width; ofcodec_ctx->height = ifcodec_ctx->height; ofcodec_ctx->time_base.den = 30; ofcodec_ctx->time_base.num = 1; printf("timebase %d %d\n", ofcodec_ctx->time_base.den, ofcodec_ctx->time_base.num); // ofcodec_ctx->bit_rate = 1000000; // ofcodec_ctx->gop_size = 5; // ofcodec_ctx->me_range = 16; // ofcodec_ctx->max_qdiff = 4; // ofcodec_ctx->qmin = 10; // ofcodec_ctx->qmax = 51; // ofcodec_ctx->qcompress = 0.6; // if (ofcodec_ctx->codec_id == AV_CODEC_ID_H264) { // av_opt_set(ofcodec_ctx->priv_data, "preset", "slow", 0); // ofcodec_ctx->max_b_frames = 1; // } out_stream->codec->codec_tag = 0; if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) { out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; } ocodec = avcodec_find_encoder(ofcodec_ctx->codec_id); if (!ocodec) { printf("find encoder err\n"); goto end; } if (avcodec_open2(ofcodec_ctx, ocodec, NULL) < 0) { printf("open encoder err\n"); goto end; } /*******************************************/ pFrame = av_frame_alloc(); pFrameYUV420 = av_frame_alloc(); pFrameBGR = av_frame_alloc(); in_buffer = (unsigned char *) av_malloc( avpicture_get_size(AV_PIX_FMT_BGR24, 640, 480)); avpicture_fill((AVPicture*) pFrameBGR, in_buffer, AV_PIX_FMT_BGR24, 640, 480); // printf("fmt %d\twidth %d\theight %d\n", pFrameBGR->format, pFrameBGR->width, // pFrameBGR->height); out_buffer = (unsigned char *) av_malloc( avpicture_get_size(AV_PIX_FMT_YUV420P, ofcodec_ctx->width, ofcodec_ctx->height)); avpicture_fill((AVPicture*) pFrameYUV420, out_buffer, AV_PIX_FMT_YUV420P, ofcodec_ctx->width, ofcodec_ctx->height); // printf("fmt %d\twidth %d\theight %d\n", pFrameYUV420->format, // pFrameYUV420->width, pFrameYUV420->height); in_conCtx = sws_getContext(ifcodec_ctx->width, ifcodec_ctx->height, ifcodec_ctx->pix_fmt, 640, 480, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); out_conCtx = sws_getContext(ifcodec_ctx->width, ifcodec_ctx->height, ifcodec_ctx->pix_fmt, ofcodec_ctx->width, ofcodec_ctx->height, ofcodec_ctx->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); image = cvCreateImageHeader(cvSize(640, 480), IPL_DEPTH_8U, 3); cvSetData(image, in_buffer, 640 * 3); // inpkg = (AVPacket*) av_malloc(sizeof(AVPacket)); // outpkg = (AVPacket*) av_malloc(sizeof(AVPacket)); start_time = av_gettime(); pFrameYUV420->format = AV_PIX_FMT_YUV420P; pFrameYUV420->width = ofcodec_ctx->width; pFrameYUV420->height = ofcodec_ctx->height; av_new_packet(&outpkg, ofcodec_ctx->width * ofcodec_ctx->height * 3); while (av_read_frame(ifmt_ctx, &inpkg) >= 0 && runFlag) { inpkg.dts = av_rescale_q_rnd(inpkg.dts, ifmt_ctx->streams[videoindex]->time_base, ifmt_ctx->streams[videoindex]->codec->time_base, (enum AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); inpkg.pts = av_rescale_q_rnd(inpkg.pts, ifmt_ctx->streams[videoindex]->time_base, ifmt_ctx->streams[videoindex]->codec->time_base, (enum AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); //decode if (inpkg.stream_index == videoindex) { ret = avcodec_decode_video2(ifcodec_ctx, pFrame, &got_picture, &inpkg); if (ret < 0) { printf("decode err\n"); exit(-1); } if (got_picture) { pFrame->pts = av_frame_get_best_effort_timestamp(pFrame); sws_scale(in_conCtx, (const unsigned char * const *) pFrame->data, pFrame->linesize, 0, ifcodec_ctx->height, pFrameBGR->data, pFrameBGR->linesize); // printf("bgr fmt %d\twidth %d\theight %d\n", pFrameBGR->format, // pFrameBGR->width, pFrameBGR->height); cvShowImage("camera", image); cvWaitKey(1); if (flag == 1) { char out_filename[30]; memset(out_filename, 0, sizeof(out_filename)); sprintf(out_filename, "%d.jpg", frame_index); printf("encode frame %d\n", frame_index++); if (!(ofmt->flags & AVFMT_NOFILE)) { ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE); if (ret < 0) { printf("could not open output url '%s'\n", out_filename); goto end; } } printf( "**************** output file info ******************\n"); av_dump_format(ofmt_ctx, 0, out_filename, 1); ret = avformat_write_header(ofmt_ctx, NULL); if (ret < 0) { printf("error occurred when opening output URL\n"); goto end; } sws_scale(out_conCtx, (const unsigned char * const *) pFrame->data, pFrame->linesize, 0, ofcodec_ctx->height, pFrameYUV420->data, pFrameYUV420->linesize); // printf("yuv420 fmt %d\twidth %d\theight %d\n", // pFrameYUV420->format, pFrameYUV420->width, // pFrameYUV420->height); got_picture = 0; pFrameYUV420->pts = pFrame->pts; ret = avcodec_encode_video2(ofcodec_ctx, &outpkg, pFrameYUV420, &got_picture); if (ret < 0) { printf("encode err\n"); goto end; } if (got_picture == 1 && flag == 1) { av_write_frame(ofmt_ctx, &outpkg); av_free_packet(&outpkg); av_write_trailer(ofmt_ctx); } flag = 0; } } } //encode av_free_packet(&inpkg); end_time = av_gettime(); printf("fps:%2f\n", (float) 1000000 / (end_time - start_time)); start_time = end_time; } end: sws_freeContext(in_conCtx); sws_freeContext(out_conCtx); free(in_buffer); free(out_buffer); av_free(pFrameYUV420); av_free(pFrameBGR); avcodec_close(ifcodec_ctx); avcodec_close(ofcodec_ctx); avformat_close_input(&ifmt_ctx); if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) avio_close(ofmt_ctx->pb); avformat_free_context(ofmt_ctx); if (ret < 0 && ret != AVERROR_EOF) { printf("Error occurred.\n"); exit(-1); } exit(0); }
代码是从标准的视频采集/转码程序改过来的,是测试程序,没有啥封装,看起来比较乱。
转载请注明出处:http://www.cnblogs.com/tla001/
一起学习,一起进步