#include "screenshot.h" #include "easylogging++.h" AVFrame *allocate_sws_frame(AVCodecContext *enc_ctx) { int ret = 0; AVFrame *sws_frame = av_frame_alloc(); if(sws_frame) { sws_frame->format = enc_ctx->pix_fmt; sws_frame->width = enc_ctx->width; sws_frame->height = enc_ctx->height; sws_frame->pict_type = AV_PICTURE_TYPE_NONE; ret = av_frame_get_buffer(sws_frame, 32); // 分配buffer if(ret <0) { av_frame_free(&sws_frame); return NULL; } } return sws_frame; } ScreenShot::ScreenShot() { } int ScreenShot::SaveJpeg(AVFrame *src_frame, const char *file_name, int jpeg_quality) { AVFormatContext* ofmt_ctx = NULL; AVOutputFormat* fmt = NULL; AVStream* video_st = NULL; AVCodecContext* enc_ctx = NULL; AVCodec* codec = NULL; AVFrame* picture = NULL; AVPacket *pkt = NULL; int got_picture = 0; int ret = 0; struct SwsContext *img_convert_ctx = NULL; ofmt_ctx = avformat_alloc_context(); //Guess format fmt = av_guess_format("mjpeg", NULL, NULL); ofmt_ctx->oformat = fmt; //Output URL if (avio_open(&ofmt_ctx->pb, file_name, AVIO_FLAG_READ_WRITE) < 0){ LOG(ERROR) <<"Couldn't open output file."; ret = -1; goto fail; } video_st = avformat_new_stream(ofmt_ctx, 0); if (video_st==NULL){ ret = -1; goto fail; } enc_ctx = video_st->codec; enc_ctx->codec_id = AV_CODEC_ID_MJPEG; // mjpeg支持的编码器 enc_ctx->codec_type = AVMEDIA_TYPE_VIDEO; enc_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P; // AV_CODEC_ID_MJPEG 支持的像素格式 enc_ctx->width = src_frame->width; enc_ctx->height = src_frame->height; enc_ctx->time_base.num = 1; enc_ctx->time_base.den = 25; //Output some information av_dump_format(ofmt_ctx, 0, file_name, 1); codec = avcodec_find_encoder(enc_ctx->codec_id); if (!codec){ LOG(ERROR) << "jpeg Codec not found."; ret = -1; goto fail; } if (avcodec_open2(enc_ctx, codec,NULL) < 0){ LOG(ERROR) << "Could not open jpeg codec."; ret = -1; goto fail; } ret = avcodec_parameters_from_context(video_st->codecpar, enc_ctx); if(ret < 0) { LOG(ERROR) << "avcodec_parameters_from_context failed"; ret = -1; goto fail; } if(src_frame->format != enc_ctx->pix_fmt) { img_convert_ctx = sws_getContext(enc_ctx->width, enc_ctx->height, (enum AVPixelFormat)src_frame->format, enc_ctx->width, enc_ctx->height, enc_ctx->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); if (!img_convert_ctx) { LOG(ERROR) << "Impossible to create scale context for the conversion fmt:" << av_get_pix_fmt_name((enum AVPixelFormat)src_frame->format) << ", s:" << enc_ctx->width << "x" << enc_ctx->height << " -> fmt:" << av_get_pix_fmt_name(enc_ctx->pix_fmt) << ", s:" << enc_ctx->width << "x" << enc_ctx->height ; ret = -1; goto fail; } } if(jpeg_quality > 0) { if(jpeg_quality > 100) jpeg_quality = 100; enc_ctx->qcompress = (float)jpeg_quality/100.f; // 0~1.0, default is 0.5 enc_ctx->qmin = 2; enc_ctx->qmax = 31; enc_ctx->max_qdiff = 3; LOG(ERROR) <<"JPEG quality is: %d" << jpeg_quality; } pkt = av_packet_alloc(); //Write Header ret = avformat_write_header(ofmt_ctx, NULL); if(ret < 0) { LOG(ERROR) <<"avformat_write_header failed"; ret = -1; goto fail; } if(img_convert_ctx) // 如果需要转换pix_fmt { // 分配转换后的frame picture = allocate_sws_frame(enc_ctx); /* make sure the frame data is writable */ ret = av_frame_make_writable(picture); ret = sws_scale(img_convert_ctx, (const uint8_t **) src_frame->data, src_frame->linesize, 0, src_frame->height, picture->data, picture->linesize); picture->pts = 0; ret = avcodec_encode_video2(enc_ctx, pkt, picture, &got_picture); } else { ret = avcodec_encode_video2(enc_ctx, pkt, src_frame, &got_picture); } if(ret < 0){ LOG(ERROR) <<"avcodec_encode_video2 Error."; ret = -1; goto fail; } if (got_picture==1){ pkt->stream_index = video_st->index; ret = av_write_frame(ofmt_ctx, pkt); if(ret < 0) { LOG(ERROR) <<"av_write_frame Error."; ret = -1; goto fail; } }else { LOG(ERROR) <<"no got_picture"; ret = -1; goto fail; } ret = 0; fail: //Write Trailer ret = av_write_trailer(ofmt_ctx); if(ret < 0) LOG(ERROR) <<"av_write_trailer Error."; if(pkt) av_packet_free(&pkt); if (enc_ctx) avcodec_close(enc_ctx); if(picture) av_frame_free(&picture); if(ofmt_ctx && ofmt_ctx->pb) avio_close(ofmt_ctx->pb); if(ofmt_ctx) avformat_free_context(ofmt_ctx); if(img_convert_ctx) sws_freeContext(img_convert_ctx); return ret; }