static u32 ts_interleave_thread_run(void *param) { GF_AbstractTSMuxer * mux = (GF_AbstractTSMuxer *) param; AVStream * video_st = mux->video_st; AVStream * audio_st = mux->audio_st; u64 audio_pts, video_pts; u64 audioSize, videoSize, videoKbps, audioKbps; u32 pass; u32 now, start; /* open the output file, if needed */ if (!(mux->oc->oformat->flags & AVFMT_NOFILE)) { if (url_fopen(&mux->oc->pb, mux->destination, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", mux->destination); return 0; } } /* write the stream header, if any */ av_write_header(mux->oc); audio_pts = video_pts = 0; // Buffering... gf_sleep(1000); now = start = gf_sys_clock(); audioSize = videoSize = 0; audioKbps = videoKbps = 0; pass = 0; while ( mux->encode) { pass++; if (0== (pass%16)) { now = gf_sys_clock(); if (now - start > 1000) { videoKbps = videoSize * 8000 / (now-start) / 1024; audioKbps = audioSize * 8000 / (now-start) / 1024; audioSize = videoSize = 0; start = now; GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("\rPTS audio="LLU" ("LLU"kbps), video="LLU" ("LLU"kbps)", audio_pts, audioKbps, video_pts, videoKbps)); } } /* write interleaved audio and video frames */ if (!video_st || (audio_pts == AV_NOPTS_VALUE && has_packet_ready(mux, mux->audioMx, &mux->audioPackets)) || ((audio_st && audio_pts < video_pts && audio_pts!= AV_NOPTS_VALUE))) { AVPacketList * pl = wait_for_packet(mux, mux->audioMx, &mux->audioPackets); if (!pl) goto exit; audio_pts = pl->pkt.pts ; audioSize+=pl->pkt.size; if (pl->pkt.pts == AV_NOPTS_VALUE) { pl->pkt.pts = 0; } if (av_interleaved_write_frame(mux->oc, &(pl->pkt)) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] : failed to write audio interleaved frame audio_pts="LLU", video_pts="LLU"\n", audio_pts, video_pts)); } gf_free(pl); } else { AVPacketList * pl = wait_for_packet(mux, mux->videoMx, &mux->videoPackets); if (!pl) goto exit; video_pts = pl->pkt.pts; /* write the compressed frame in the media file */ if (0 && audio_pts != AV_NOPTS_VALUE && audio_pts > video_pts && pl->next) { u32 skipped = 0; u64 first = video_pts; /* We may be too slow... */ gf_mx_p(mux->videoMx); while (video_pts < audio_pts && pl->next) { AVPacketList * old = pl; // We skip frames... pl = pl->next; video_pts = pl->pkt.pts; skipped++; gf_free(old); } mux->videoPackets = pl->next; gf_mx_v(mux->videoMx); if (skipped > 0) GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("Skipped %u video frames, frame was "LLU", but is now "LLU"\n", skipped, first, video_pts)); } videoSize+=pl->pkt.size; video_pts = pl->pkt.pts; // * video_st->time_base.num / video_st->time_base.den; assert( video_pts); if (av_interleaved_write_frame(mux->oc, &(pl->pkt)) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] : failed to write video interleaved frame audio_pts="LLU", video_pts="LLU"\n", audio_pts, video_pts)); } gf_free(pl); } gf_sleep(1); } exit: GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[AVRedirect] Ending TS thread...\n")); av_write_trailer(mux->oc); if (!(mux->oc->oformat->flags & AVFMT_NOFILE)) { /* close the output file */ url_fclose(mux->oc->pb); } return 0; }
int main(int argc, char* argv[]) { AVFormatContext* in_fctx; AVCodecContext* in_cctx; AVCodec* in_codec; const char* in_filename; const char* out_filename; char* decoded_buf; char* output_buf; char* resample_buf; char* before_encoding_buf; int ret = 0; if (argc != 3) { printf("./audio_convertor input ouput\n"); return -1; } //in_filename = "../input/input.aac"; //out_filename = "output/aac2mp3.mp3"; in_filename = argv[1]; out_filename = argv[2]; decoded_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); output_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); resample_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); before_encoding_buf = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); avcodec_register_all(); av_register_all(); in_fctx = avformat_alloc_context(); ret = av_open_input_file(&in_fctx, in_filename, NULL, 0, NULL); if ( ret != 0 ) { printf("open input audio file[%s] fail\n", in_filename); return -1; } ret = av_find_stream_info(in_fctx); if ( ret < 0 ) { printf("find stream in audio file[%s] fail\n", in_filename); return -1; } dump_format(in_fctx, 0, in_filename, 0); //这里我们假设,如果一个文件包含多个音频流, //只对第一个音频流做转码,而对于视频流则忽略 int i; int ast_index = -1; for (i = 0; i<(int)in_fctx->nb_streams; ++i) { if (in_fctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { ast_index = i; break; } } if (ast_index == -1) { printf("there is not any audio stream in file[%s]\n", in_filename); return 0; } else { printf("find audio stream in file[%s]\n", in_filename); } in_cctx = in_fctx->streams[ast_index]->codec; //in_cctx->codec_id = CODEC_ID_GSM; in_codec = avcodec_find_decoder(in_cctx->codec_id); if (!in_codec) { printf("find decoder for codec_id[%d] fail, file[%s]\n", in_cctx->codec_id, in_filename); return -1; } ret = avcodec_open(in_cctx, in_codec); if (ret >= 0) { printf("open codec[name:%s] for stream[idx:%d] of file[%s]\n", in_codec->name, ast_index, in_filename); } // 输出部分初始化 AVOutputFormat* out_fmt; AVFormatContext* out_fctx; AVCodecContext* out_cctx = NULL; out_fmt = av_guess_format(NULL, out_filename, NULL); if (!out_fmt) { printf("Could not deduce output format from file extension: using MPEG-3.\n"); out_fmt = av_guess_format("mp3", NULL, NULL); } if (!out_fmt) { fprintf(stderr, "Could not find suitable output format\n"); exit(1); } out_fctx = avformat_alloc_context(); if (!out_fctx) { fprintf(stderr, "avformat_alloc_context fail\n"); exit(1); } out_fctx->oformat = out_fmt; out_cctx = output_decode_init(in_cctx, out_fctx, out_fmt->audio_codec); if (!out_cctx) { fprintf(stderr, "output_codec_init fail\n"); exit(1); } /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(out_fctx, NULL) < 0) { fprintf(stderr, "Invalid output format parameters\n"); exit(1); } dump_format(out_fctx, 0, out_filename, 1); output_decode_open(out_cctx); /* open the output file */ if (!(out_fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&out_fctx->pb, out_filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", out_filename); exit(1); } } /* write the stream header, if any */ if(av_write_header(out_fctx) < 0) { fprintf(stderr, "Could not write header for output file\n"); return -1; } int decoded_size; AVPacket in_packet; AVPacket out_packet; ReSampleContext *rs_ctx = NULL; /* 参考链接:http://hi.baidu.com/wg_wang/item/34396781d20b4b1ec316270b 两点需要注意: (1) 从输入文件中按帧读取数据,解码,按照输出文件的要求,编码,并按帧写入到输出文件中。 在这里,由于sample_rate和channels可能不同,需要对音频数据进行重采样。 (2) 由于不同编码类型对一帧音频的数据要求不同,可能需要将输入数据保存起来,直到够输出的编码使用, 或者,一帧的输入数据可能需要被多次输出。 这样,要求初始化重采样以及libavutil提供的fifo(libavutils/fifo.h声明)以临时保存数据。 举个例子:aac的frame_size=1024,mp3的frame_size=1152。若不用这个fifo,则生成的mp3文件是有问题的 */ // 设置从采样 rs_ctx = av_audio_resample_init( out_cctx->channels, in_cctx->channels, out_cctx->sample_rate, in_cctx->sample_rate, out_cctx->sample_fmt, in_cctx->sample_fmt, 16, 10, 0, 0.8); AVFifoBuffer *iofifo; iofifo = av_fifo_alloc(AVCODEC_MAX_AUDIO_FRAME_SIZE*2); av_init_packet(&in_packet); av_init_packet(&out_packet); while (av_read_frame(in_fctx, &in_packet) >= 0) { while (in_packet.size > 0) { int used_size; decoded_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; used_size = avcodec_decode_audio3(in_cctx, (int16_t *)decoded_buf, &decoded_size, &in_packet); if (used_size < 0) { printf("avcodec_decode_audio3 fail\n"); exit(1); } int bs, frame_bytes; bs = audio_resample(rs_ctx, (short *)resample_buf, (short *)decoded_buf, decoded_size/(in_cctx->channels*g_in_bytes)); ret = av_fifo_generic_write(iofifo, (uint8_t *)resample_buf, bs*out_cctx->channels*g_out_bytes, NULL); //ret = av_fifo_generic_write(iofifo, (uint8_t *)decoded_buf, in_cctx->frame_size*in_cctx->channels*g_out_bytes, NULL); frame_bytes = out_cctx->frame_size * g_out_bytes * out_cctx->channels; while(av_fifo_size(iofifo) >= frame_bytes) { ret = av_fifo_generic_read(iofifo, before_encoding_buf, frame_bytes, NULL); out_packet.size = avcodec_encode_audio(out_cctx, (uint8_t*)output_buf, frame_bytes, (short *)before_encoding_buf); out_packet.data = (uint8_t *)output_buf; av_write_frame(out_fctx, &out_packet); } in_packet.size -= used_size; in_packet.data += used_size; } } /* write the trailer, if any */ av_write_trailer(out_fctx); if (!(out_fmt->flags & AVFMT_NOFILE)) { /* close the output file */ url_fclose(out_fctx->pb); } }
int main(int argc, char *argv[]) { IDeckLinkIterator *deckLinkIterator = CreateDeckLinkIteratorInstance(); DeckLinkCaptureDelegate *delegate; BMDDisplayMode selectedDisplayMode = bmdModeNTSC; int displayModeCount = 0; int exitStatus = 1; int connection = 0, camera = 0, i=0; int ch; HRESULT result; pthread_mutex_init(&sleepMutex, NULL); pthread_cond_init(&sleepCond, NULL); av_register_all(); if (!deckLinkIterator) { fprintf(stderr, "This application requires the DeckLink drivers installed.\n"); goto bail; } // Parse command line options while ((ch = getopt(argc, argv, "?hc:s:f:a:m:n:F:C:I:")) != -1) { switch (ch) { case 'm': g_videoModeIndex = atoi(optarg); break; case 'c': g_audioChannels = atoi(optarg); if (g_audioChannels != 2 && g_audioChannels != 8 && g_audioChannels != 16) { fprintf(stderr, "Invalid argument: Audio Channels must be either 2, 8 or 16\n"); goto bail; } break; case 's': g_audioSampleDepth = atoi(optarg); if (g_audioSampleDepth != 16 && g_audioSampleDepth != 32) { fprintf(stderr, "Invalid argument: Audio Sample Depth must be either 16 bits or 32 bits\n"); goto bail; } break; case 'f': g_videoOutputFile = optarg; break; case 'n': g_maxFrames = atoi(optarg); break; case 'F': fmt = av_guess_format(optarg, NULL, NULL); break; case 'I': connection = atoi(optarg); break; case 'C': camera = atoi(optarg); break; case '?': case 'h': usage(0); } } /* Connect to the first DeckLink instance */ do { result = deckLinkIterator->Next(&deckLink); } while(i++<camera); if (result != S_OK) { fprintf(stderr, "No DeckLink PCI cards found.\n"); goto bail; } if (deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&deckLinkInput) != S_OK) goto bail; result = deckLink->QueryInterface(IID_IDeckLinkConfiguration, (void**)&deckLinkConfiguration); if (result != S_OK) { fprintf(stderr, "Could not obtain the IDeckLinkConfiguration interface - result = %08x\n", result); goto bail; } //XXX make it generic if (connection == 1) { // video compuesto + audio analogico deckLinkConfiguration->SetInt(bmdDeckLinkConfigVideoInputConnection, bmdVideoConnectionComposite); deckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioInputConnection, bmdAudioConnectionAnalog); }else if (connection == 2) { // video componentes + audio analogico deckLinkConfiguration->SetInt(bmdDeckLinkConfigVideoInputConnection, bmdVideoConnectionComponent); deckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioInputConnection, bmdAudioConnectionAnalog); }else if (connection == 3) { // HDMI video + audio deckLinkConfiguration->SetInt(bmdDeckLinkConfigVideoInputConnection, bmdVideoConnectionHDMI); deckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioInputConnection, bmdAudioConnectionEmbedded); }else if (connection == 4) { // SDI video + audio deckLinkConfiguration->SetInt(bmdDeckLinkConfigVideoInputConnection, bmdVideoConnectionSDI); deckLinkConfiguration->SetInt(bmdDeckLinkConfigAudioInputConnection, bmdAudioConnectionEmbedded); } delegate = new DeckLinkCaptureDelegate(); deckLinkInput->SetCallback(delegate); // Obtain an IDeckLinkDisplayModeIterator to enumerate the display modes supported on output result = deckLinkInput->GetDisplayModeIterator(&displayModeIterator); if (result != S_OK) { fprintf(stderr, "Could not obtain the video output display mode iterator - result = %08x\n", result); goto bail; } if (!fmt) fmt = av_guess_format(NULL, g_videoOutputFile, NULL); if (g_videoModeIndex < 0) { fprintf(stderr, "No video mode specified\n"); usage(0); } selectedDisplayMode = -1; while (displayModeIterator->Next(&displayMode) == S_OK) { if (g_videoModeIndex == displayModeCount) { selectedDisplayMode = displayMode->GetDisplayMode(); break; } displayModeCount++; displayMode->Release(); } oc = avformat_alloc_context(); oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", g_videoOutputFile); fmt->video_codec = CODEC_ID_RAWVIDEO; fmt->audio_codec = CODEC_ID_PCM_S16LE; video_st = add_video_stream(oc, fmt->video_codec); audio_st = add_audio_stream(oc, fmt->audio_codec); av_set_parameters(oc, NULL); if (!(fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&oc->pb, oc->filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", oc->filename); exit(1); } } if (selectedDisplayMode < 0) { fprintf(stderr, "Invalid mode %d specified\n", g_videoModeIndex); goto bail; } result = deckLinkInput->EnableVideoInput(selectedDisplayMode, bmdFormat8BitYUV, 0); if(result != S_OK) { fprintf(stderr, "Failed to enable video input. Is another application using the card?\n"); goto bail; } result = deckLinkInput->EnableAudioInput(bmdAudioSampleRate48kHz, g_audioSampleDepth, g_audioChannels); if(result != S_OK) { goto bail; } av_write_header(oc); result = deckLinkInput->StartStreams(); if(result != S_OK) { goto bail; } // All Okay. exitStatus = 0; // Block main thread until signal occurs pthread_mutex_lock(&sleepMutex); pthread_cond_wait(&sleepCond, &sleepMutex); pthread_mutex_unlock(&sleepMutex); fprintf(stderr, "Stopping Capture\n"); bail: if (displayModeIterator != NULL) { displayModeIterator->Release(); displayModeIterator = NULL; } if (deckLinkInput != NULL) { deckLinkInput->Release(); deckLinkInput = NULL; } if (deckLink != NULL) { deckLink->Release(); deckLink = NULL; } if (deckLinkIterator != NULL) deckLinkIterator->Release(); if (oc != NULL) { av_write_trailer(oc); if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ url_fclose(oc->pb); } } return exitStatus; }
glw_rec_t * glw_rec_init(const char *filename, int width, int height, int fps) { extern int concurrency; AVCodec *c; struct glw_rec *gr = calloc(1, sizeof(glw_rec_t)); gr->width = width; gr->height = height; gr->fps = fps; gr->fmt = av_guess_format(NULL, filename, NULL); if(gr->fmt == NULL) { TRACE(TRACE_ERROR, "GLWREC", "Unable to record to %s -- Unknown file format", filename); return NULL; } gr->oc = avformat_alloc_context(); gr->oc->oformat = gr->fmt; snprintf(gr->oc->filename, sizeof(gr->oc->filename), "%s", filename); gr->v_st = av_new_stream(gr->oc, 0); gr->v_ctx = gr->v_st->codec; gr->v_ctx->codec_type = AVMEDIA_TYPE_VIDEO; gr->v_ctx->codec_id = CODEC_ID_FFVHUFF; gr->v_ctx->width = width; gr->v_ctx->height = height; gr->v_ctx->time_base.den = fps; gr->v_ctx->time_base.num = 1; gr->v_ctx->pix_fmt = PIX_FMT_RGB32; gr->v_ctx->coder_type = 1; if(av_set_parameters(gr->oc, NULL) < 0) { TRACE(TRACE_ERROR, "GLWREC", "Unable to record to %s -- Invalid output format parameters", filename); return NULL; } dump_format(gr->oc, 0, filename, 1); c = avcodec_find_encoder(gr->v_ctx->codec_id); if(avcodec_open(gr->v_ctx, c)) { TRACE(TRACE_ERROR, "GLWREC", "Unable to record to %s -- Unable to open video codec", filename); return NULL; } gr->v_ctx->thread_count = concurrency; if(url_fopen(&gr->oc->pb, filename, URL_WRONLY) < 0) { TRACE(TRACE_ERROR, "GLWREC", "Unable to record to %s -- Unable to open file for writing", filename); return NULL; } /* write the stream header, if any */ av_write_header(gr->oc); gr->vbuf_size = 2000000; gr->vbuf_ptr = av_malloc(gr->vbuf_size); return gr; }
/// Create a video writer object that uses FFMPEG inline bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, double fps, int width, int height, bool is_color ) { icvInitFFMPEG_internal(); CodecID codec_id = CODEC_ID_NONE; int err, codec_pix_fmt; double bitrate_scale = 1; close(); // check arguments if( !filename ) return false; if(fps <= 0) return false; // we allow frames of odd width or height, but in this case we truncate // the rightmost column/the bottom row. Probably, this should be handled more elegantly, // but some internal functions inside FFMPEG swscale require even width/height. width &= -2; height &= -2; if( width <= 0 || height <= 0 ) return false; /* auto detect the output format from the name and fourcc code. */ #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) fmt = av_guess_format(NULL, filename, NULL); #else fmt = guess_format(NULL, filename, NULL); #endif if (!fmt) return false; /* determine optimal pixel format */ if (is_color) { input_pix_fmt = PIX_FMT_BGR24; } else { input_pix_fmt = PIX_FMT_GRAY8; } /* Lookup codec_id for given fourcc */ #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ) return false; #else const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL}; if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ) return false; #endif // alloc memory for context #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) oc = avformat_alloc_context(); #else oc = av_alloc_format_context(); #endif assert (oc); /* set file name */ oc->oformat = fmt; _snprintf(oc->filename, sizeof(oc->filename), "%s", filename); /* set some options */ oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ // set a few optimal pixel formats for lossless codecs of interest.. switch (codec_id) { #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) case CODEC_ID_JPEGLS: // BGR24 or GRAY8 depending on is_color... codec_pix_fmt = input_pix_fmt; break; #endif case CODEC_ID_HUFFYUV: codec_pix_fmt = PIX_FMT_YUV422P; break; case CODEC_ID_MJPEG: case CODEC_ID_LJPEG: codec_pix_fmt = PIX_FMT_YUVJ420P; bitrate_scale = 3; break; case CODEC_ID_RAWVIDEO: codec_pix_fmt = input_pix_fmt == PIX_FMT_GRAY8 || input_pix_fmt == PIX_FMT_GRAY16LE || input_pix_fmt == PIX_FMT_GRAY16BE ? input_pix_fmt : PIX_FMT_YUV420P; break; default: // good for lossy formats, MPEG, etc. codec_pix_fmt = PIX_FMT_YUV420P; break; } double bitrate = MIN(bitrate_scale*fps*width*height, (double)INT_MAX/2); // TODO -- safe to ignore output audio stream? video_st = icv_add_video_stream_FFMPEG(oc, codec_id, width, height, (int)(bitrate + 0.5), fps, codec_pix_fmt); /* set the output parameters (must be done even if no parameters). */ #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) if (av_set_parameters(oc, NULL) < 0) { return false; } #endif #if 0 #if FF_API_DUMP_FORMAT dump_format(oc, 0, filename, 1); #else av_dump_format(oc, 0, filename, 1); #endif #endif /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (!video_st){ return false; } AVCodec *codec; AVCodecContext *c; #if LIBAVFORMAT_BUILD > 4628 c = (video_st->codec); #else c = &(video_st->codec); #endif c->codec_tag = fourcc; /* find the video encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { fprintf(stderr, "Could not find encoder for codec id %d: %s", c->codec_id, icvFFMPEGErrStr( #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0) AVERROR_ENCODER_NOT_FOUND #else -1 #endif )); return false; } s64 lbit_rate = (s64)c->bit_rate; lbit_rate += (bitrate / 2); lbit_rate = std::min(lbit_rate, (s64)INT_MAX); c->bit_rate_tolerance = (int)lbit_rate; c->bit_rate = (int)lbit_rate; /* open the codec */ if ((err= #if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) avcodec_open2(c, codec, NULL) #else avcodec_open(c, codec) #endif ) < 0) { fprintf(stderr, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err)); return false; } outbuf = NULL; if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* assume we will never get codec output with more than 4 bytes per pixel... */ outbuf_size = width*height*4; outbuf = (uint8_t *) av_malloc(outbuf_size); } bool need_color_convert; need_color_convert = (c->pix_fmt != input_pix_fmt); /* allocate the encoded raw picture */ picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); if (!picture) { return false; } /* if the output format is not our input format, then a temporary picture of the input format is needed too. It is then converted to the required output format */ input_picture = NULL; if ( need_color_convert ) { input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false); if (!input_picture) { return false; } } /* open the output file, if needed */ if (!(fmt->flags & AVFMT_NOFILE)) { #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0) if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) #else if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) #endif { return false; } } #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) /* write the stream header, if any */ err=avformat_write_header(oc, NULL); #else err=av_write_header( oc ); #endif if(err < 0) { close(); remove(filename); return false; } frame_width = width; frame_height = height; ok = true; return true; }
int start_up(EncoderJob &jobSpec) { jobSpec.p = new Pests(); jobSpec.oc = avformat_alloc_context(); if (!jobSpec.oc) { fprintf(stderr, "Memory error\n"); jobSpec.IsValid = false; return 3; } jobSpec.oc->oformat = jobSpec.fmt; sprintf(jobSpec.oc->filename, "%s-%05u.ts", jobSpec.BaseDirectory, jobSpec.SegmentNumber); // Set video codecs: jobSpec.fmt->video_codec = CODEC_ID_H264; // Video codec. Requires FFmpeg to be built with libx264. jobSpec.fmt->audio_codec = CODEC_ID_MP3; //CODEC_ID_AAC; // AAC is not working so well. Will use MP3 instead. jobSpec.video_st = NULL; jobSpec.audio_st = NULL; if (jobSpec.fmt->video_codec != CODEC_ID_NONE) { jobSpec.video_st = add_video_stream(jobSpec.oc, jobSpec.fmt->video_codec, jobSpec); } if (jobSpec.fmt->audio_codec != CODEC_ID_NONE) { jobSpec.audio_st = add_audio_stream(jobSpec, jobSpec.oc, jobSpec.fmt->audio_codec); } /*if (av_set_parameters(jobSpec.oc, NULL) < 0) { fprintf(stderr, "Invalid output format parameters\n"); jobSpec.IsValid = false; return 4; }*/ /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (jobSpec.video_st) { open_video(jobSpec, jobSpec.oc, jobSpec.video_st); } if (jobSpec.audio_st) { open_audio(jobSpec.oc, jobSpec.audio_st); } #ifdef NEW_M2TS jobSpec.fmt->flags |= AVFMT_NOFILE; // we'll write our own, thanks! int track_ids[2] = {120, 121}; uint8_t track_types[2] = {Pests::TT_H264, Pests::TT_MpegAudio}; jobSpec.p->StartFile(jobSpec.oc->filename, track_ids, track_types, 2); // 120 = video, 121 = audio #else // open the output file, if needed if (!(jobSpec.fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&jobSpec.oc->pb, jobSpec.oc->filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", jobSpec.oc->filename); jobSpec.IsValid = false; return 5; } av_write_header(jobSpec.oc); } #endif // All done OK, validate and return. // From this point on, the developer MUST call CloseEncoderJob() before exiting. jobSpec.IsValid = true; return 0; }
/* This function opens an mpeg file using the new libavformat method. Both mpeg1 * and mpeg4 are supported. However, if the current ffmpeg version doesn't allow * mpeg1 with non-standard framerate, the open will fail. Timelapse is a special * case and is tested separately. */ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, unsigned char *y, unsigned char *u, unsigned char *v, int width, int height, int rate, int bps, int vbr) { AVCodecContext *c; AVCodec *codec; struct ffmpeg *ffmpeg; int is_mpeg1; /* Allocate space for our ffmpeg structure. This structure contains all the * codec and image information we need to generate movies. * FIXME when motion exits we should close the movie to ensure that * ffmpeg is freed. */ ffmpeg = mymalloc(sizeof(struct ffmpeg)); memset(ffmpeg, 0, sizeof(struct ffmpeg)); ffmpeg->vbr = vbr; /* store codec name in ffmpeg->codec, with buffer overflow check */ snprintf(ffmpeg->codec, sizeof(ffmpeg->codec), "%s", ffmpeg_video_codec); /* allocation the output media context */ ffmpeg->oc = av_mallocz(sizeof(AVFormatContext)); if (!ffmpeg->oc) { motion_log(LOG_ERR, 1, "Memory error while allocating output media context"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Setup output format */ ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename); if (!ffmpeg->oc->oformat) { ffmpeg_cleanups(ffmpeg); return NULL; } snprintf(ffmpeg->oc->filename, sizeof(ffmpeg->oc->filename), "%s", filename); /* Create a new video stream and initialize the codecs */ ffmpeg->video_st = NULL; if (ffmpeg->oc->oformat->video_codec != CODEC_ID_NONE) { ffmpeg->video_st = av_new_stream(ffmpeg->oc, 0); if (!ffmpeg->video_st) { motion_log(LOG_ERR, 1, "av_new_stream - could not alloc stream"); ffmpeg_cleanups(ffmpeg); return NULL; } } else { /* We did not get a proper video codec. */ motion_log(LOG_ERR, 0, "Failed to obtain a proper video codec"); ffmpeg_cleanups(ffmpeg); return NULL; } ffmpeg->c = c = AVSTREAM_CODEC_PTR(ffmpeg->video_st); c->codec_id = ffmpeg->oc->oformat->video_codec; c->codec_type = CODEC_TYPE_VIDEO; is_mpeg1 = c->codec_id == CODEC_ID_MPEG1VIDEO; if (strcmp(ffmpeg_video_codec, "ffv1") == 0) c->strict_std_compliance = -2; /* Uncomment to allow non-standard framerates. */ //c->strict_std_compliance = -1; /* Set default parameters */ c->bit_rate = bps; c->width = width; c->height = height; #if LIBAVCODEC_BUILD >= 4754 /* frame rate = 1/time_base, so we set 1/rate, not rate/1 */ c->time_base.num = 1; c->time_base.den = rate; #else c->frame_rate = rate; c->frame_rate_base = 1; #endif /* LIBAVCODEC_BUILD >= 4754 */ if (debug_level >= CAMERA_DEBUG) motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__,rate); if (vbr) c->flags |= CODEC_FLAG_QSCALE; /* Set codec specific parameters. */ /* set intra frame distance in frames depending on codec */ c->gop_size = is_mpeg1 ? 10 : 12; /* some formats want stream headers to be separate */ if (!strcmp(ffmpeg->oc->oformat->name, "mp4") || !strcmp(ffmpeg->oc->oformat->name, "mov") || !strcmp(ffmpeg->oc->oformat->name, "3gp")) { c->flags |= CODEC_FLAG_GLOBAL_HEADER; } /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(ffmpeg->oc, NULL) < 0) { motion_log(LOG_ERR, 0, "ffmpeg av_set_parameters error: Invalid output format parameters"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Dump the format settings. This shows how the various streams relate to each other */ //dump_format(ffmpeg->oc, 0, filename, 1); /* Now that all the parameters are set, we can open the video codec and allocate the necessary encode buffers */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { motion_log(LOG_ERR, 1, "Codec not found"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Set the picture format - need in ffmpeg starting round April-May 2005 */ c->pix_fmt = PIX_FMT_YUV420P; /* Get a mutex lock. */ pthread_mutex_lock(&global_lock); /* open the codec */ if (avcodec_open(c, codec) < 0) { /* Release the lock. */ pthread_mutex_unlock(&global_lock); motion_log(LOG_ERR, 1, "avcodec_open - could not open codec"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Release the lock. */ pthread_mutex_unlock(&global_lock); ffmpeg->video_outbuf = NULL; if (!(ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* XXX: API change will be done */ /* ffmpeg->video_outbuf_size = 20000; */ ffmpeg->video_outbuf_size = ffmpeg->c->width * 256; ffmpeg->video_outbuf = mymalloc(ffmpeg->video_outbuf_size); } /* allocate the encoded raw picture */ ffmpeg->picture = avcodec_alloc_frame(); if (!ffmpeg->picture) { motion_log(LOG_ERR, 1, "avcodec_alloc_frame - could not alloc frame"); ffmpeg_cleanups(ffmpeg); return NULL; } /* set variable bitrate if requested */ if (ffmpeg->vbr) ffmpeg->picture->quality = ffmpeg->vbr; /* set the frame data */ ffmpeg->picture->data[0] = y; ffmpeg->picture->data[1] = u; ffmpeg->picture->data[2] = v; ffmpeg->picture->linesize[0] = ffmpeg->c->width; ffmpeg->picture->linesize[1] = ffmpeg->c->width / 2; ffmpeg->picture->linesize[2] = ffmpeg->c->width / 2; /* open the output file, if needed */ if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { char file_proto[256]; /* Use append file protocol for mpeg1, to get the append behavior from * url_fopen, but no protocol (=> default) for other codecs. */ if (is_mpeg1) snprintf(file_proto, sizeof(file_proto), APPEND_PROTO ":%s", filename); else snprintf(file_proto, sizeof(file_proto), "%s", filename); if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { /* path did not exist? */ if (errno == ENOENT) { /* create path for file (don't use file_proto)... */ if (create_path(filename) == -1) { ffmpeg_cleanups(ffmpeg); return NULL; } /* and retry opening the file (use file_proto) */ if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { motion_log(LOG_ERR, 1, "url_fopen - error opening file %s",filename); ffmpeg_cleanups(ffmpeg); return NULL; } /* Permission denied */ } else if (errno == EACCES) { motion_log(LOG_ERR, 1, "url_fopen - error opening file %s" " ... check access rights to target directory", filename); ffmpeg_cleanups(ffmpeg); return NULL; } else { motion_log(LOG_ERR, 1, "Error opening file %s", filename); ffmpeg_cleanups(ffmpeg); return NULL; } } } /* write the stream header, if any */ av_write_header(ffmpeg->oc); return ffmpeg; }
int main(int argc, char **argv) { if(argc != 5) { fprintf(stderr, "Usage: %s <segment length> <output location> <filename prefix> <encoding profile>\n", argv[0]); return 1; } struct config_info config; memset(&config, 0, sizeof(struct config_info)); config.segment_length = atoi(argv[1]); config.temp_directory = argv[2]; config.filename_prefix = argv[3]; config.encoding_profile = argv[4]; config.input_filename = "pipe://1"; char *output_filename = malloc(sizeof(char) * (strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10)); if (!output_filename) { fprintf(stderr, "Segmenter error: Could not allocate space for output filenames\n"); exit(1); } // ------------------ Done parsing input -------------- av_register_all(); AVInputFormat *input_format = av_find_input_format("mpegts"); if (!input_format) { fprintf(stderr, "Segmenter error: Could not find MPEG-TS demuxer\n"); exit(1); } AVFormatContext *input_context = NULL; int ret = av_open_input_file(&input_context, config.input_filename, input_format, 0, NULL); if (ret != 0) { fprintf(stderr, "Segmenter error: Could not open input file, make sure it is an mpegts file: %d\n", ret); exit(1); } if (av_find_stream_info(input_context) < 0) { fprintf(stderr, "Segmenter error: Could not read stream information\n"); exit(1); } AVOutputFormat *output_format = av_guess_format("mpegts", NULL, NULL); if (!output_format) { fprintf(stderr, "Segmenter error: Could not find MPEG-TS muxer\n"); exit(1); } AVFormatContext *output_context = avformat_alloc_context(); if (!output_context) { fprintf(stderr, "Segmenter error: Could not allocated output context"); exit(1); } output_context->oformat = output_format; int video_index = -1; int audio_index = -1; AVStream *video_stream; AVStream *audio_stream; int i; for (i = 0; i < input_context->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (input_context->streams[i]->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: video_index = i; input_context->streams[i]->discard = AVDISCARD_NONE; video_stream = add_output_stream(output_context, input_context->streams[i]); break; case AVMEDIA_TYPE_AUDIO: audio_index = i; input_context->streams[i]->discard = AVDISCARD_NONE; audio_stream = add_output_stream(output_context, input_context->streams[i]); break; default: input_context->streams[i]->discard = AVDISCARD_ALL; break; } } if (av_set_parameters(output_context, NULL) < 0) { fprintf(stderr, "Segmenter error: Invalid output format parameters\n"); exit(1); } av_dump_format(output_context, 0, config.filename_prefix, 1); if(video_index >= 0) { AVCodec *codec = avcodec_find_decoder(video_stream->codec->codec_id); if (!codec) { fprintf(stderr, "Segmenter error: Could not find video decoder, key frames will not be honored\n"); } if (avcodec_open(video_stream->codec, codec) < 0) { fprintf(stderr, "Segmenter error: Could not open video decoder, key frames will not be honored\n"); } } unsigned int output_index = 1; snprintf(output_filename, strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10, "%s/%s-%05u.ts", config.temp_directory, config.filename_prefix, output_index++); if (avio_open(&output_context->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename); exit(1); } if (av_write_header(output_context)) { fprintf(stderr, "Segmenter error: Could not write mpegts header to first output file\n"); exit(1); } unsigned int first_segment = 1; unsigned int last_segment = 0; double prev_segment_time = 0; int decode_done; do { double segment_time; AVPacket packet; decode_done = av_read_frame(input_context, &packet); if (decode_done < 0) { break; } if (av_dup_packet(&packet) < 0) { fprintf(stderr, "Segmenter error: Could not duplicate packet"); av_free_packet(&packet); break; } if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY)) { segment_time = (double)video_stream->pts.val * video_stream->time_base.num / video_stream->time_base.den; } else if (video_index < 0) { segment_time = (double)audio_stream->pts.val * audio_stream->time_base.num / audio_stream->time_base.den; } else { segment_time = prev_segment_time; } // done writing the current file? if (segment_time - prev_segment_time >= config.segment_length) { avio_flush(output_context->pb); avio_close(output_context->pb); output_transfer_command(first_segment, ++last_segment, 0, config.encoding_profile); snprintf(output_filename, strlen(config.temp_directory) + 1 + strlen(config.filename_prefix) + 10, "%s/%s-%05u.ts", config.temp_directory, config.filename_prefix, output_index++); if (avio_open(&output_context->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Segmenter error: Could not open '%s'\n", output_filename); break; } prev_segment_time = segment_time; } ret = av_interleaved_write_frame(output_context, &packet); if (ret < 0) { fprintf(stderr, "Segmenter error: Could not write frame of stream: %d\n", ret); } else if (ret > 0) { fprintf(stderr, "Segmenter info: End of stream requested\n"); av_free_packet(&packet); break; } av_free_packet(&packet); } while (!decode_done); av_write_trailer(output_context); if (video_index >= 0) { avcodec_close(video_stream->codec); } for(i = 0; i < output_context->nb_streams; i++) { av_freep(&output_context->streams[i]->codec); av_freep(&output_context->streams[i]); } avio_close(output_context->pb); av_free(output_context); output_transfer_command(first_segment, ++last_segment, 1, config.encoding_profile); return 0; }
int main(int argc, char **argv) { double prev_segment_time = 0; unsigned int output_index = 1; AVInputFormat *ifmt; AVOutputFormat *ofmt; AVFormatContext *ic = NULL; AVFormatContext *oc; AVStream *video_st = NULL; AVStream *audio_st = NULL; AVCodec *codec; char *output_filename; char *remove_filename; int video_index; int audio_index; unsigned int first_segment = 1; unsigned int last_segment = 0; int write_index = 1; int decode_done; char *dot; int ret; int i; int remove_file; struct sigaction act; int opt; int longindex; char *endptr; struct options_t options = {0}; static const char *optstring = "i:d:p:m:u:n:ovh?"; static const struct option longopts[] = { { "input", required_argument, NULL, 'i' }, { "duration", required_argument, NULL, 'd' }, { "output-prefix", required_argument, NULL, 'p' }, { "m3u8-file", required_argument, NULL, 'm' }, { "url-prefix", required_argument, NULL, 'u' }, { "num-segments", required_argument, NULL, 'n' }, { "ondemand", required_argument, NULL, 'o' }, { "help", no_argument, NULL, 'h' }, { 0, 0, 0, 0 } }; /* Set some defaults */ options.segment_duration = 10; do { opt = getopt_long(argc, argv, optstring, longopts, &longindex ); switch (opt) { case 'i': options.input_file = optarg; if (!strcmp(options.input_file, "-")) { options.input_file = "pipe:"; } break; case 'd': options.segment_duration = strtol(optarg, &endptr, 10); if (optarg == endptr || options.segment_duration < 0 || options.segment_duration == -LONG_MAX) { fprintf(stderr, "Segment duration time (%s) invalid\n", optarg); exit(1); } break; case 'p': options.output_prefix = optarg; break; case 'm': options.m3u8_file = optarg; break; case 'u': options.url_prefix = optarg; break; case 's': options.num_segments = strtol(optarg, &endptr, 10); if (optarg == endptr || options.num_segments < 0 || options.num_segments >= LONG_MAX) { fprintf(stderr, "Maximum number of ts files (%s) invalid\n", optarg); exit(1); } break; case 'o': options.ondemand = 1; break; case 'h': display_usage(); break; } } while (opt != -1); /* Check required args where set*/ if (options.input_file == NULL) { fprintf(stderr, "Please specify an input file.\n"); exit(1); } if (options.output_prefix == NULL) { fprintf(stderr, "Please specify an putput prefix.\n"); exit(1); } if (options.m3u8_file == NULL) { fprintf(stderr, "Please specify an output file.\n"); exit(1); } if (options.url_prefix == NULL) { fprintf(stderr, "Please specify a url prefix.\n"); exit(1); } av_register_all(); remove_filename = malloc(sizeof(char) * (strlen(options.output_prefix) + 15)); if (!remove_filename) { fprintf(stderr, "Could not allocate space for remove filenames\n"); exit(1); } output_filename = malloc(sizeof(char) * (strlen(options.output_prefix) + 15)); if (!output_filename) { fprintf(stderr, "Could not allocate space for output filenames\n"); exit(1); } options.tmp_m3u8_file = malloc(strlen(options.m3u8_file) + 2); if (!options.tmp_m3u8_file) { fprintf(stderr, "Could not allocate space for temporary index filename\n"); exit(1); } // Use a dotfile as a temporary file strncpy(options.tmp_m3u8_file, options.m3u8_file, strlen(options.m3u8_file) + 2); dot = strrchr(options.tmp_m3u8_file, '/'); dot = dot ? dot + 1 : options.tmp_m3u8_file; memmove(dot + 1, dot, strlen(dot)); *dot = '.'; ifmt = av_find_input_format("mpegts"); if (!ifmt) { fprintf(stderr, "Could not find MPEG-TS demuxer\n"); exit(1); } ret = av_open_input_file(&ic, options.input_file, ifmt, 0, NULL); if (ret != 0) { fprintf(stderr, "Could not open input file, make sure it is an mpegts file: %d\n", ret); exit(1); } if (av_find_stream_info(ic) < 0) { fprintf(stderr, "Could not read stream information\n"); exit(1); } ofmt = av_guess_format("mpegts", NULL, NULL); if (!ofmt) { fprintf(stderr, "Could not find MPEG-TS muxer\n"); exit(1); } oc = avformat_alloc_context(); if (!oc) { fprintf(stderr, "Could not allocated output context"); exit(1); } oc->oformat = ofmt; video_index = -1; audio_index = -1; for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (ic->streams[i]->codec->codec_type) { case CODEC_TYPE_VIDEO: video_index = i; ic->streams[i]->discard = AVDISCARD_NONE; video_st = add_output_stream(oc, ic->streams[i]); break; case CODEC_TYPE_AUDIO: audio_index = i; ic->streams[i]->discard = AVDISCARD_NONE; audio_st = add_output_stream(oc, ic->streams[i]); break; default: ic->streams[i]->discard = AVDISCARD_ALL; break; } } if (av_set_parameters(oc, NULL) < 0) { fprintf(stderr, "Invalid output format parameters\n"); exit(1); } dump_format(oc, 0, options.output_prefix, 1); codec = avcodec_find_decoder(video_st->codec->codec_id); if (!codec) { fprintf(stderr, "Could not find video decoder, key frames will not be honored\n"); } if (avcodec_open(video_st->codec, codec) < 0) { fprintf(stderr, "Could not open video decoder, key frames will not be honored\n"); } snprintf(output_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, output_index++); if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); exit(1); } if (av_write_header(oc)) { fprintf(stderr, "Could not write mpegts header to first output file\n"); exit(1); } write_index = !write_index_file(options, first_segment, last_segment, 0); /* Setup signals */ memset(&act, 0, sizeof(act)); act.sa_handler = &handler; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); do { double segment_time; AVPacket packet; if (terminate) { break; } decode_done = av_read_frame(ic, &packet); if (decode_done < 0) { break; } if (av_dup_packet(&packet) < 0) { fprintf(stderr, "Could not duplicate packet"); av_free_packet(&packet); break; } if (packet.stream_index == video_index && (packet.flags & PKT_FLAG_KEY)) { segment_time = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den; } else if (video_index < 0) { segment_time = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den; } else { segment_time = prev_segment_time; } if (segment_time - prev_segment_time >= options.segment_duration) { put_flush_packet(oc->pb); url_fclose(oc->pb); if (options.num_segments && (int)(last_segment - first_segment) >= options.num_segments - 1) { remove_file = 1; first_segment++; } else { remove_file = 0; } if (write_index) { write_index = !write_index_file(options, first_segment, ++last_segment, 0); } if (remove_file) { snprintf(remove_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, first_segment - 1); remove(remove_filename); } snprintf(output_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, output_index++); if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); break; } prev_segment_time = segment_time; } ret = av_interleaved_write_frame(oc, &packet); if (ret < 0) { fprintf(stderr, "Warning: Could not write frame of stream\n"); } else if (ret > 0) { fprintf(stderr, "End of stream requested\n"); av_free_packet(&packet); break; } av_free_packet(&packet); } while (!decode_done); av_write_trailer(oc); avcodec_close(video_st->codec); for(i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } url_fclose(oc->pb); av_free(oc); if (options.num_segments && (int)(last_segment - first_segment) >= options.num_segments - 1) { remove_file = 1; first_segment++; } else { remove_file = 0; } if (write_index) { write_index_file(options, first_segment, ++last_segment, 1); } if (remove_file) { snprintf(remove_filename, strlen(options.output_prefix) + 15, "%s-%u.ts", options.output_prefix, first_segment - 1); remove(remove_filename); } return 0; }
int VideoFFmpegWriter::execute( boost::uint8_t* in_buffer, int in_width, int in_height, PixelFormat in_pixelFormat ) { _error = IGNORE_FINISH; AVOutputFormat* fmt = 0; fmt = guess_format( _format.c_str(), NULL, NULL ); if( !fmt ) { fmt = guess_format( NULL, filename().c_str(), NULL ); if( !fmt ) { std::cerr << "ffmpegWriter: could not deduce output format from file extension." << std::endl; return false; } } if( !_avformatOptions ) _avformatOptions = avformat_alloc_context(); _avformatOptions->oformat = fmt; snprintf( _avformatOptions->filename, sizeof( _avformatOptions->filename ), "%s", filename().c_str() ); if( !_stream ) { _stream = av_new_stream( _avformatOptions, 0 ); if( !_stream ) { std::cout << "ffmpegWriter: out of memory." << std::endl; return false; } CodecID codecId = fmt->video_codec; AVCodec* userCodec = avcodec_find_encoder_by_name( _codec.c_str() ); if( userCodec ) codecId = userCodec->id; _stream->codec->codec_id = codecId; _stream->codec->codec_type = CODEC_TYPE_VIDEO; _stream->codec->bit_rate = _bitRate; _stream->codec->bit_rate_tolerance = _bitRateTolerance; _stream->codec->width = width(); _stream->codec->height = height(); _stream->codec->time_base = av_d2q( 1.0 / _fps, 100 ); _stream->codec->gop_size = _gopSize; if( _bFrames ) { _stream->codec->max_b_frames = _bFrames; _stream->codec->b_frame_strategy = 0; _stream->codec->b_quant_factor = 2.0; } _stream->codec->mb_decision = _mbDecision; _stream->codec->pix_fmt = _out_pixelFormat; if( !strcmp( _avformatOptions->oformat->name, "mp4" ) || !strcmp( _avformatOptions->oformat->name, "mov" ) || !strcmp( _avformatOptions->oformat->name, "3gp" ) || !strcmp( _avformatOptions->oformat->name, "flv" ) ) _stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if( av_set_parameters( _avformatOptions, NULL ) < 0 ) { std::cout << "ffmpegWriter: unable to set parameters." << std::endl; freeFormat(); return false; } dump_format( _avformatOptions, 0, filename().c_str(), 1 ); AVCodec* videoCodec = avcodec_find_encoder( codecId ); if( !videoCodec ) { std::cout << "ffmpegWriter: unable to find codec." << std::endl; freeFormat(); return false; } if( avcodec_open( _stream->codec, videoCodec ) < 0 ) { std::cout << "ffmpegWriter: unable to open codec." << std::endl; freeFormat(); return false; } if( !( fmt->flags & AVFMT_NOFILE ) ) { if( url_fopen( &_avformatOptions->pb, filename().c_str(), URL_WRONLY ) < 0 ) { std::cout << "ffmpegWriter: unable to open file." << std::endl; return false; } } av_write_header( _avformatOptions ); } _error = CLEANUP; AVFrame* in_frame = avcodec_alloc_frame(); avcodec_get_frame_defaults( in_frame ); avpicture_fill( (AVPicture*)in_frame, in_buffer, in_pixelFormat, in_width, in_height ); AVFrame* out_frame = avcodec_alloc_frame(); avcodec_get_frame_defaults( out_frame ); int out_picSize = avpicture_get_size( _out_pixelFormat, width(), height() ); boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize ); avpicture_fill( (AVPicture*) out_frame, out_buffer, _out_pixelFormat, width(), height() ); _sws_context = sws_getCachedContext( _sws_context, in_width, in_height, in_pixelFormat, width(), height(), _out_pixelFormat, SWS_BICUBIC, NULL, NULL, NULL ); std::cout << "ffmpegWriter: input format: " << pixelFormat_toString( in_pixelFormat ) << std::endl; std::cout << "ffmpegWriter: output format: " << pixelFormat_toString( _out_pixelFormat ) << std::endl; if( !_sws_context ) { std::cout << "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." << std::endl; return false; } int error = sws_scale( _sws_context, in_frame->data, in_frame->linesize, 0, height(), out_frame->data, out_frame->linesize ); if( error < 0 ) { std::cout << "ffmpeg-conversion failed (" << in_pixelFormat << "->" << _out_pixelFormat << ")." << std::endl; return false; } int ret = 0; if( ( _avformatOptions->oformat->flags & AVFMT_RAWPICTURE ) != 0 ) { AVPacket pkt; av_init_packet( &pkt ); pkt.flags |= PKT_FLAG_KEY; pkt.stream_index = _stream->index; pkt.data = (boost::uint8_t*) out_frame; pkt.size = sizeof( AVPicture ); ret = av_interleaved_write_frame( _avformatOptions, &pkt ); } else { boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize ); ret = avcodec_encode_video( _stream->codec, out_buffer, out_picSize, out_frame ); if( ret > 0 ) { AVPacket pkt; av_init_packet( &pkt ); if( _stream->codec->coded_frame && _stream->codec->coded_frame->pts != static_cast<boost::int64_t>( AV_NOPTS_VALUE ) ) // static_cast<unsigned long> ( pkt.pts = av_rescale_q( _stream->codec->coded_frame->pts, _stream->codec->time_base, _stream->time_base ); if( _stream->codec->coded_frame && _stream->codec->coded_frame->key_frame ) pkt.flags |= PKT_FLAG_KEY; pkt.stream_index = _stream->index; pkt.data = out_buffer; pkt.size = ret; ret = av_interleaved_write_frame( _avformatOptions, &pkt ); } av_free( out_buffer ); } av_free( out_buffer ); av_free( out_frame ); av_free( in_frame ); // in_buffer not free (function parameter) if( ret ) { std::cout << "ffmpegWriter: error writing frame to file." << std::endl; return false; } _error = SUCCESS; return true; }
/// close video output stream and free associated memory void CvVideoWriter_FFMPEG::close() { unsigned i; // nothing to do if already released if ( !picture ) return; /* no more frame to compress. The codec has a latency of a few frames if using B frames, so we get the last frames by passing the same picture again */ // TODO -- do we need to account for latency here? /* write the trailer, if any */ av_write_trailer(oc); // free pictures #if LIBAVFORMAT_BUILD > 4628 if( video_st->codec->pix_fmt != input_pix_fmt){ #else if( video_st->codec.pix_fmt != input_pix_fmt){ #endif cvFree(&(picture->data[0])); } av_free(picture); if (input_picture) { av_free(input_picture); } /* close codec */ #if LIBAVFORMAT_BUILD > 4628 avcodec_close(video_st->codec); #else avcodec_close(&(video_st->codec)); #endif av_free(outbuf); /* free the streams */ for(i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0) url_fclose(oc->pb); #else url_fclose(&oc->pb); #endif } /* free the stream */ av_free(oc); cvReleaseImage( &temp_image ); init(); } /// Create a video writer object that uses FFMPEG bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, double fps, CvSize frameSize, bool is_color ) { CV_FUNCNAME("CvVideoWriter_FFMPEG::open"); CodecID codec_id = CODEC_ID_NONE; int err, codec_pix_fmt, bitrate_scale=64; __BEGIN__; close(); // check arguments assert (filename); assert (fps > 0); assert (frameSize.width > 0 && frameSize.height > 0); // tell FFMPEG to register codecs av_register_all (); /* auto detect the output format from the name and fourcc code. */ fmt = guess_format(NULL, filename, NULL); if (!fmt) { CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG does not recognize the given file extension"); } /* determine optimal pixel format */ if (is_color) { input_pix_fmt = PIX_FMT_BGR24; } else { input_pix_fmt = PIX_FMT_GRAY8; } // alloc memory for context oc = av_alloc_format_context(); assert (oc); /* set file name */ oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", filename); /* set some options */ oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ /* Lookup codec_id for given fourcc */ #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0) if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ){ CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." ); } #else { const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL}; if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ){ CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." ); } } #endif // set a few optimal pixel formats for lossless codecs of interest.. switch (codec_id) { #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0) case CODEC_ID_JPEGLS: // BGR24 or GRAY8 depending on is_color... codec_pix_fmt = input_pix_fmt; break; #endif case CODEC_ID_HUFFYUV: codec_pix_fmt = PIX_FMT_YUV422P; break; case CODEC_ID_MJPEG: case CODEC_ID_LJPEG: codec_pix_fmt = PIX_FMT_YUVJ420P; bitrate_scale = 128; break; case CODEC_ID_RAWVIDEO: default: // good for lossy formats, MPEG, etc. codec_pix_fmt = PIX_FMT_YUV420P; break; } // TODO -- safe to ignore output audio stream? video_st = icv_add_video_stream_FFMPEG(oc, codec_id, frameSize.width, frameSize.height, frameSize.width*frameSize.height*bitrate_scale, fps, codec_pix_fmt); /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(oc, NULL) < 0) { CV_ERROR(CV_StsBadArg, "Invalid output format parameters"); } dump_format(oc, 0, filename, 1); /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (!video_st){ CV_ERROR(CV_StsBadArg, "Couldn't open video stream"); } AVCodec *codec; AVCodecContext *c; #if LIBAVFORMAT_BUILD > 4628 c = (video_st->codec); #else c = &(video_st->codec); #endif c->codec_tag = fourcc; /* find the video encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { CV_ERROR(CV_StsBadArg, "codec not found"); } /* open the codec */ if ( (err=avcodec_open(c, codec)) < 0) { char errtext[256]; sprintf(errtext, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err)); CV_ERROR(CV_StsBadArg, errtext); } outbuf = NULL; if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* assume we will never get codec output with more than 4 bytes per pixel... */ outbuf_size = frameSize.width*frameSize.height*4; outbuf = (uint8_t *) av_malloc(outbuf_size); } bool need_color_convert; need_color_convert = (c->pix_fmt != input_pix_fmt); /* allocate the encoded raw picture */ picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); if (!picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } /* if the output format is not our input format, then a temporary picture of the input format is needed too. It is then converted to the required output format */ input_picture = NULL; if ( need_color_convert ) { input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false); if (!input_picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } } /* open the output file, if needed */ if (!(fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) { CV_ERROR(CV_StsBadArg, "Couldn't open output file for writing"); } } /* write the stream header, if any */ av_write_header( oc ); __END__; return true; }
void FFMpegManager::create(const QString &filePath, int formatId, const QStringList &paths, const QSize &size, int fps) { #ifdef HAVE_FFMPEG AVOutputFormat *fmt = guess_format(0, filePath.toLatin1().data(), 0); if ( !fmt ) { fmt = guess_format("mpeg", NULL, NULL); } // AVFormatParameters params, *ap = ¶ms; switch(formatId) { case ExportInterface::ASF: { } break; case ExportInterface::AVI: { fmt->video_codec = CODEC_ID_MSMPEG4V3; // video_st->codec.codec_tag = 0; } break; case ExportInterface::MOV: { } break; case ExportInterface::MPEG: { } break; case ExportInterface::RM: { } break; case ExportInterface::SWF: { } break; case ExportInterface::GIF: { // AVImageFormat *imageFormat = guess_image_format(filePath.toLatin1().data()); // // memset(ap, 0, sizeof(*ap)); // ap->image_format = imageFormat; } break; default: break; } AVFormatContext *oc = av_alloc_format_context(); if ( !oc ) { dError() << "Error while export"; return; } oc->oformat = fmt; snprintf(oc->filename, sizeof(oc->filename), "%s", filePath.toLatin1().data()); AVStream *video_st = addVideoStream(oc, fmt->video_codec, size.width(), size.height(), fps); if ( !video_st ) { dError() << "Can't add video stream"; return; } if (av_set_parameters(oc, 0) < 0) { dError() << "Invalid output format parameters"; return ; } dump_format(oc, 0, filePath.toLatin1().data(), 1); if (!openVideo(oc, video_st) ) { dError() << "Can't open video"; return; } if (!(fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&oc->pb, filePath.toLatin1().data(), URL_WRONLY) < 0) { dError() << "Could not open " << filePath.toLatin1().data(); return; } } av_write_header(oc); double video_pts = 0.0; foreach(QString imagePath, paths) { if (video_st) { video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den; } else { video_pts = 0.0; } if (!video_st || video_pts >= m_streamDuration ) { break; } if (! writeVideoFrame(imagePath, oc, video_st, fps) ) { break; } } closeVideo(oc, video_st); av_write_trailer(oc); for(int i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]); } if (!(fmt->flags & AVFMT_NOFILE)) { /* close the output file */ url_fclose(&oc->pb); } av_free(oc); #endif }
void VideoStream::OpenStream() { /* now that all the parameters are set, we can open the video codecs and allocate the necessary encode buffers */ if ( ost ) { #if ZM_FFMPEG_SVN AVCodecContext *c = ost->codec; #else AVCodecContext *c = &ost->codec; #endif /* find the video encoder */ AVCodec *codec = avcodec_find_encoder(c->codec_id); if ( !codec ) { Panic( "codec not found" ); } /* open the codec */ #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) if ( avcodec_open(c, codec) < 0 ) #else if ( avcodec_open2(c, codec, 0) < 0 ) #endif { Panic( "Could not open codec" ); } /* allocate the encoded raw picture */ opicture = avcodec_alloc_frame(); if ( !opicture ) { Panic( "Could not allocate opicture" ); } int size = avpicture_get_size( c->pix_fmt, c->width, c->height); uint8_t *opicture_buf = (uint8_t *)av_malloc(size); if ( !opicture_buf ) { av_free(opicture); Panic( "Could not allocate opicture" ); } avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, c->width, c->height ); /* if the output format is not identical to the input format, then a temporary picture is needed too. It is then converted to the required output format */ tmp_opicture = NULL; if ( c->pix_fmt != pf ) { tmp_opicture = avcodec_alloc_frame(); if ( !tmp_opicture ) { Panic( "Could not allocate temporary opicture" ); } int size = avpicture_get_size( pf, c->width, c->height); uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc(size); if (!tmp_opicture_buf) { av_free( tmp_opicture ); Panic( "Could not allocate temporary opicture" ); } avpicture_fill( (AVPicture *)tmp_opicture, tmp_opicture_buf, pf, c->width, c->height ); } } /* open the output file, if needed */ if ( !(of->flags & AVFMT_NOFILE) ) { #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1) if ( avio_open(&ofc->pb, filename, AVIO_FLAG_WRITE) < 0 ) #else if ( url_fopen(&ofc->pb, filename, AVIO_FLAG_WRITE) < 0 ) #endif { Fatal( "Could not open '%s'", filename ); } } video_outbuf = NULL; if ( !(ofc->oformat->flags & AVFMT_RAWPICTURE) ) { /* allocate output buffer */ /* XXX: API change will be done */ video_outbuf_size = 200000; video_outbuf = (uint8_t *)malloc(video_outbuf_size); } /* write the stream header, if any */ #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) av_write_header(ofc); #else avformat_write_header(ofc, NULL); #endif }
int main(int argc, char **argv) { const char *input; const char *output_prefix; double segment_duration; char *segment_duration_check; const char *index; char *tmp_index; const char *http_prefix; long max_tsfiles = 0; char *max_tsfiles_check; double prev_segment_time = 0; unsigned int output_index = 1; AVInputFormat *ifmt; AVOutputFormat *ofmt; AVFormatContext *ic = NULL; AVFormatContext *oc; AVStream *video_st; AVStream *audio_st; AVCodec *codec; char *output_filename; char *remove_filename; int video_index; int audio_index; unsigned int first_segment = 1; unsigned int last_segment = 0; int write_index = 1; int decode_done; char *dot; int ret; int i; int remove_file; if (argc < 6 || argc > 7) { fprintf(stderr, "Usage: %s <input MPEG-TS file> <segment duration in seconds> <output MPEG-TS file prefix> <output m3u8 index file> <http prefix> [<segment window size>]\n", argv[0]); exit(1); } av_register_all(); input = argv[1]; if (!strcmp(input, "-")) { input = "pipe:"; } segment_duration = strtod(argv[2], &segment_duration_check); if (segment_duration_check == argv[2] || segment_duration == HUGE_VAL || segment_duration == -HUGE_VAL) { fprintf(stderr, "Segment duration time (%s) invalid\n", argv[2]); exit(1); } output_prefix = argv[3]; index = argv[4]; http_prefix=argv[5]; if (argc == 7) { max_tsfiles = strtol(argv[6], &max_tsfiles_check, 10); if (max_tsfiles_check == argv[6] || max_tsfiles < 0 || max_tsfiles >= INT_MAX) { fprintf(stderr, "Maximum number of ts files (%s) invalid\n", argv[6]); exit(1); } } remove_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15)); if (!remove_filename) { fprintf(stderr, "Could not allocate space for remove filenames\n"); exit(1); } output_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15)); if (!output_filename) { fprintf(stderr, "Could not allocate space for output filenames\n"); exit(1); } tmp_index = malloc(strlen(index) + 2); if (!tmp_index) { fprintf(stderr, "Could not allocate space for temporary index filename\n"); exit(1); } strncpy(tmp_index, index, strlen(index) + 2); dot = strrchr(tmp_index, '/'); dot = dot ? dot + 1 : tmp_index; for (i = strlen(tmp_index) + 1; i > dot - tmp_index; i--) { tmp_index[i] = tmp_index[i - 1]; } *dot = '.'; ifmt = av_find_input_format("mpegts"); if (!ifmt) { fprintf(stderr, "Could not find MPEG-TS demuxer\n"); exit(1); } ret = av_open_input_file(&ic, input, ifmt, 0, NULL); if (ret != 0) { fprintf(stderr, "Could not open input file, make sure it is an mpegts file: %d\n", ret); exit(1); } if (av_find_stream_info(ic) < 0) { fprintf(stderr, "Could not read stream information\n"); exit(1); } ofmt = av_guess_format("mpegts", NULL, NULL); if (!ofmt) { fprintf(stderr, "Could not find MPEG-TS muxer\n"); exit(1); } oc = avformat_alloc_context(); if (!oc) { fprintf(stderr, "Could not allocated output context"); exit(1); } oc->oformat = ofmt; video_index = -1; audio_index = -1; for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (ic->streams[i]->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: video_index = i; ic->streams[i]->discard = AVDISCARD_NONE; video_st = add_output_stream(oc, ic->streams[i]); break; case AVMEDIA_TYPE_AUDIO: audio_index = i; ic->streams[i]->discard = AVDISCARD_NONE; audio_st = add_output_stream(oc, ic->streams[i]); break; default: ic->streams[i]->discard = AVDISCARD_ALL; break; } } if (av_set_parameters(oc, NULL) < 0) { fprintf(stderr, "Invalid output format parameters\n"); exit(1); } dump_format(oc, 0, output_prefix, 1); codec = avcodec_find_decoder(video_st->codec->codec_id); if (!codec) { fprintf(stderr, "Could not find video decoder, key frames will not be honored\n"); } if (avcodec_open(video_st->codec, codec) < 0) { fprintf(stderr, "Could not open video decoder, key frames will not be honored\n"); } snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index++); if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); exit(1); } if (av_write_header(oc)) { fprintf(stderr, "Could not write mpegts header to first output file\n"); exit(1); } write_index = !write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, last_segment, 0, max_tsfiles); do { double segment_time; AVPacket packet; decode_done = av_read_frame(ic, &packet); if (decode_done < 0) { break; } if (av_dup_packet(&packet) < 0) { fprintf(stderr, "Could not duplicate packet"); av_free_packet(&packet); break; } if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY)) { segment_time = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den; } else if (video_index < 0) { segment_time = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den; } else { segment_time = prev_segment_time; } if (segment_time - prev_segment_time >= segment_duration) { put_flush_packet(oc->pb); url_fclose(oc->pb); if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) { remove_file = 1; first_segment++; } else { remove_file = 0; } if (write_index) { write_index = !write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, ++last_segment, 0, max_tsfiles); } if (remove_file) { snprintf(remove_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, first_segment - 1); remove(remove_filename); } snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index++); if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); break; } prev_segment_time = segment_time; } ret = av_interleaved_write_frame(oc, &packet); if (ret < 0) { fprintf(stderr, "Warning: Could not write frame of stream\n"); } else if (ret > 0) { fprintf(stderr, "End of stream requested\n"); av_free_packet(&packet); break; } av_free_packet(&packet); } while (!decode_done); av_write_trailer(oc); avcodec_close(video_st->codec); for(i = 0; i < oc->nb_streams; i++) { av_freep(&oc->streams[i]->codec); av_freep(&oc->streams[i]); } url_fclose(oc->pb); av_free(oc); if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) { remove_file = 1; first_segment++; } else { remove_file = 0; } if (write_index) { write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, ++last_segment, 1, max_tsfiles); } if (remove_file) { snprintf(remove_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, first_segment - 1); remove(remove_filename); } return 0; }
uint8_t lavMuxer::open(const char *filename,uint32_t inbitrate, ADM_MUXER_TYPE type, aviInfo *info,uint32_t videoExtraDataSize, uint8_t *videoExtraData, WAVHeader *audioheader,uint32_t audioextraSize,uint8_t *audioextraData) { AVCodecContext *c; _type=type; _fps1000=info->fps1000; switch(_type) { case MUXER_TS: fmt=guess_format("mpegts", NULL, NULL); break; case MUXER_DVD: fmt = guess_format("dvd", NULL, NULL); break; case MUXER_VCD: fmt = guess_format("vcd", NULL, NULL); break; case MUXER_SVCD: fmt = guess_format("svcd", NULL, NULL); break; case MUXER_MP4: fmt = guess_format("mp4", NULL, NULL); break; case MUXER_PSP: fmt = guess_format("psp", NULL, NULL); break; default: fmt=NULL; } if (!fmt) { printf("Lav:Cannot guess format\n"); return 0; } oc = av_alloc_format_context(); if (!oc) { printf("Lav:Cannot allocate context\n"); return 0; } oc->oformat = fmt; snprintf(oc->filename,1000,"file://%s",filename); // Video //________ video_st = av_new_stream(oc, 0); if (!video_st) { printf("Lav: new stream failed\n"); return 0; } c = video_st->codec; switch(_type) { case MUXER_MP4: if(isMpeg4Compatible(info->fcc)) { c->codec_id = CODEC_ID_MPEG4; c->has_b_frames=1; // in doubt... }else { if(isH264Compatible(info->fcc)) { c->has_b_frames=1; // in doubt... c->codec_id = CODEC_ID_H264; c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); c->codec->name=ADM_strdup("H264"); } else { c->codec_id = CODEC_ID_MPEG4; // Default value printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); //return 0; } } if(videoExtraDataSize) { c->extradata=videoExtraData; c->extradata_size= videoExtraDataSize; } c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_TS: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_DVD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_VCD: c->codec_id = CODEC_ID_MPEG1VIDEO; c->rc_buffer_size=8*1024*40; c->rc_max_rate=1152*1000; c->rc_min_rate=1152*1000; c->bit_rate=1152*1000; break; case MUXER_SVCD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*112; c->rc_max_rate=2500*1000; c->rc_min_rate=0*1000; if(!inbitrate) c->bit_rate=2040*1000; else c->bit_rate=inbitrate; break; default: ADM_assert(0); } c->codec_type = CODEC_TYPE_VIDEO; c->flags=CODEC_FLAG_QSCALE; c->width = info->width; c->height = info->height; switch(_fps1000) { case 25000: c->time_base= (AVRational){1001,25025}; //c->frame_rate = 25025; //c->frame_rate_base = 1001; break; case 23976: /* c->frame_rate = 24000; c->frame_rate_base = 1001; break; */ if(_type==MUXER_MP4) { c->time_base= (AVRational){1001,24000}; break; } case 29970: c->time_base= (AVRational){1001,30000}; //c->frame_rate = 30000; //c->frame_rate_base = 1001; break; default: if(_type==MUXER_MP4) { c->time_base= (AVRational){1000,_fps1000}; break; } else { GUI_Error_HIG(_("Incompatible frame rate"), NULL); return 0; } } c->gop_size=15; c->max_b_frames=2; c->has_b_frames=1; // Audio //________ if(audioheader) { audio_st = av_new_stream(oc, 1); if (!audio_st) { printf("Lav: new stream failed\n"); return 0; } c = audio_st->codec; c->frame_size=1024; //For AAC mainly, sample per frame switch(audioheader->encoding) { case WAV_AC3: c->codec_id = CODEC_ID_AC3;break; case WAV_MP2: c->codec_id = CODEC_ID_MP2;break; case WAV_MP3: #warning FIXME : Probe deeper c->frame_size=1152; c->codec_id = CODEC_ID_MP3; break; case WAV_PCM: // One chunk is 10 ms (1/100 of fq) c->frame_size=4; c->codec_id = CODEC_ID_PCM_S16LE;break; case WAV_AAC: c->extradata=audioextraData; c->extradata_size= audioextraSize; c->codec_id = CODEC_ID_AAC; break; default: printf("Cant mux that ! audio\n"); printf("Cant mux that ! audio\n"); c->codec_id = CODEC_ID_MP2; return 0; break; } c->codec_type = CODEC_TYPE_AUDIO; c->bit_rate = audioheader->byterate*8; c->rc_buffer_size=(c->bit_rate/(2*8)); // 500 ms worth _audioFq=c->sample_rate = audioheader->frequency; c->channels = audioheader->channels; _audioByterate=audioheader->byterate; } // /audio //---------------------- switch(_type) { case MUXER_MP4: oc->mux_rate=10080*1000; // Needed ? break; case MUXER_TS: oc->mux_rate=10080*1000; break; case MUXER_DVD: oc->packet_size=2048; oc->mux_rate=10080*1000; break; case MUXER_VCD: oc->packet_size=2324; oc->mux_rate=2352 * 75 * 8; break; case MUXER_SVCD: oc->packet_size=2324; oc->mux_rate=2*2352 * 75 * 8; // ? break; default: ADM_assert(0); } oc->preload=AV_TIME_BASE/10; // 100 ms preloading oc->max_delay=200*1000; // 500 ms if (av_set_parameters(oc, NULL) < 0) { printf("Lav: set param failed \n"); return 0; } if (url_fopen(&(oc->pb), filename, URL_WRONLY) < 0) { printf("Lav: Failed to open file :%s\n",filename); return 0; } av_write_header(oc); dump_format(oc, 0, filename, 1); printf("lavformat mpeg muxer initialized\n"); _running=1; one=(1000*1000*1000)/_fps1000; _curDTS=one; return 1; }
/// Create a video writer object that uses FFMPEG CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char * filename, int fourcc, double fps, CvSize frameSize, int /*is_color*/ ) { CV_FUNCNAME("cvCreateVideoWriter"); CvAVI_FFMPEG_Writer * writer = NULL; __BEGIN__; // check arguments assert (filename); assert (fps > 0); assert (frameSize.width > 0 && frameSize.height > 0); // allocate memory for structure... writer = (CvAVI_FFMPEG_Writer *) cvAlloc( sizeof(CvAVI_FFMPEG_Writer)); memset (writer, 0, sizeof (*writer)); // tell FFMPEG to register codecs av_register_all (); /* auto detect the output format from the name. default is mpeg. */ writer->fmt = guess_format(NULL, filename, NULL); if (!writer->fmt) { CV_ERROR( CV_StsUnsupportedFormat, "Could not deduce output format from file extension"); //writer->fmt = guess_format("mpeg", NULL, NULL); } // alloc memory for context writer->oc = av_alloc_format_context(); assert (writer->oc); /* set file name */ writer->oc->oformat = writer->fmt; snprintf(writer->oc->filename, sizeof(writer->oc->filename), "%s", filename); // TODO -- safe to ignore output audio stream? writer->video_st = icv_add_video_stream_FFMPEG(writer->oc, fourcc, frameSize.width, frameSize.height, 800000, fps, PIX_FMT_YUV420P); /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(writer->oc, NULL) < 0) { CV_ERROR(CV_StsBadArg, "Invalid output format parameters"); } dump_format(writer->oc, 0, filename, 1); /* now that all the parameters are set, we can open the audio and video codecs and allocate the necessary encode buffers */ if (!writer->video_st){ CV_ERROR(CV_StsBadArg, "Couldn't open video stream"); } AVCodec *codec; AVCodecContext *c; #if LIBAVFORMAT_BUILD > 4628 c = (writer->video_st->codec); #else c = &(writer->video_st->codec); #endif /* find the video encoder */ codec = avcodec_find_encoder(c->codec_id); if (!codec) { CV_ERROR(CV_StsBadArg, "codec not found"); } /* open the codec */ if (avcodec_open(c, codec) < 0) { char errtext[256]; sprintf(errtext, "Could not open codec '%s'", codec->name); CV_ERROR(CV_StsBadArg, errtext); } // printf("Using codec %s\n", codec->name); writer->outbuf = NULL; if (!(writer->oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* XXX: API change will be done */ writer->outbuf_size = 200000; writer->outbuf = (uint8_t *) malloc(writer->outbuf_size); } bool need_color_convert; need_color_convert = c->pix_fmt != PIX_FMT_BGR24; /* allocate the encoded raw picture */ writer->picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert); if (!writer->picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } /* if the output format is not YUV420P, then a temporary YUV420P picture is needed too. It is then converted to the required output format */ writer->rgb_picture = NULL; if ( need_color_convert ) { writer->rgb_picture = icv_alloc_picture_FFMPEG(PIX_FMT_BGR24, c->width, c->height, false); if (!writer->rgb_picture) { CV_ERROR(CV_StsNoMem, "Could not allocate picture"); } } /* open the output file, if needed */ if (!(writer->fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&writer->oc->pb, filename, URL_WRONLY) < 0) { CV_ERROR(CV_StsBadArg, "Couldn't open output file for writing"); } } /* write the stream header, if any */ av_write_header( writer->oc ); __END__; // return what we got return (CvVideoWriter *) writer; }
oz::ffmpeg_encoder* oz::ffmpeg_encoder::create( const char *path, unsigned width, unsigned height, const std::pair<int, int>& fps, int bit_rate ) { impl *m = new impl; for (;;) { m->format = av_guess_format(NULL, path, NULL); if (!m->format) break; if ((m->format->flags & AVFMT_NOFILE) || (m->format->video_codec == CODEC_ID_NONE)) break; m->formatCtx = avformat_alloc_context(); if (!m->formatCtx) break; m->formatCtx->oformat = m->format; { #if LIBAVFORMAT_VERSION_MAJOR >= 54 m->stream = avformat_new_stream(m->formatCtx, 0); #else m->stream = av_new_stream(m->formatCtx, 0); #endif if (!m->stream) { fprintf(stderr, "Could not alloc stream\n"); break; } m->codecCtx = m->stream->codec; m->codecCtx->codec_type = AVMEDIA_TYPE_VIDEO; if (strcmp(m->format->name, "avi") == 0) { m->codecCtx->codec_id = CODEC_ID_HUFFYUV; //CODEC_ID_RAWVIDEO; } else { m->codecCtx->codec_id = m->format->video_codec; } AVCodec *codec = avcodec_find_encoder(m->codecCtx->codec_id); if (!codec) break; if (strcmp(m->format->name, "avi") == 0) { m->codecCtx->pix_fmt = PIX_FMT_RGB32; //PIX_FMT_BGR24; } else { if (codec->pix_fmts) m->codecCtx->pix_fmt = codec->pix_fmts[0]; else m->codecCtx->pix_fmt = PIX_FMT_YUV420P; } m->codecCtx->bit_rate = 8000000; m->codecCtx->width = width; /* resolution must be a multiple of two */ m->codecCtx->height = height; m->codecCtx->time_base.num = fps.second; m->codecCtx->time_base.den = fps.first; m->codecCtx->gop_size = 12; /* emit one intra frame every twelve frames at most */ if(m->formatCtx->oformat->flags & AVFMT_GLOBALHEADER) m->codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; #if LIBAVFORMAT_VERSION_MAJOR >= 54 if (avcodec_open2(m->codecCtx, codec, NULL) < 0) break; #else if (avcodec_open(m->codecCtx, codec) < 0) break; #endif if (!(m->formatCtx->oformat->flags & AVFMT_RAWPICTURE)) { m->output_size = m->codecCtx->width * m->codecCtx->height * 4; m->output_buffer = (uint8_t*)av_malloc(m->output_size); } if (!alloc_frame(&m->frame1, &m->buffer1, m->codecCtx->pix_fmt, m->codecCtx->width, m->codecCtx->height)) break; if (!alloc_frame(&m->frame0, &m->buffer0, PIX_FMT_RGB32, m->codecCtx->width, m->codecCtx->height)) break; } #if LIBAVFORMAT_VERSION_MAJOR >= 54 if (avio_open(&m->formatCtx->pb, path, AVIO_FLAG_WRITE) < 0) break; avformat_write_header(m->formatCtx, NULL); #else if (url_fopen(&m->formatCtx->pb, path, URL_WRONLY) < 0) break; av_write_header(m->formatCtx); #endif m->swsCtx = sws_getContext( m->codecCtx->width, m->codecCtx->height, PIX_FMT_RGB32, m->codecCtx->width, m->codecCtx->height, m->codecCtx->pix_fmt, SWS_POINT, NULL, NULL, NULL ); if (!m->swsCtx) break; return new ffmpeg_encoder(m); } delete m; return 0; }
static VALUE segmenter_segment(VALUE klass, VALUE input_, VALUE output_prefix_, VALUE duration_ ) { const char *input; const char *output_prefix; int segment_duration; long max_tsfiles = 0; double prev_segment_time = 0; unsigned int output_index = 1; AVInputFormat *ifmt; AVOutputFormat *ofmt; AVFormatContext *ic = NULL; AVFormatContext *oc; AVStream *video_st; AVStream *audio_st; AVCodec *codec; char *output_filename; char *remove_filename; int video_index; int audio_index; unsigned int first_segment = 1; unsigned int last_segment = 0; int decode_done; int ret; unsigned int i; int remove_file; bool soundOnly = false; VALUE sArray = rb_ary_new(); av_register_all(); av_log_set_level(AV_LOG_PANIC); input = RSTRING_PTR(input_); output_prefix = RSTRING_PTR(output_prefix_); segment_duration = (FIX2INT(duration_)); char *folder = dirname2(strdup(input)); remove_filename = malloc(sizeof(char) * (strlen(output_prefix) + 15)); if (!remove_filename) { rb_raise(rb_eNoMemError, "Could not allocate space for remove filenames"); } output_filename = malloc(sizeof(char) * (strlen(output_prefix) + strlen(folder) + 15)); if (!output_filename) { rb_raise(rb_eNoMemError, "Could not allocate space for output filenames"); } ifmt = av_find_input_format("mpegts"); if (!ifmt) { rb_raise(rb_eException, "Could not find MPEG-TS demuxer"); } ret = av_open_input_file(&ic, input, ifmt, 0, NULL); if (ret != 0) { rb_raise(rb_eException, "Could not open input file, make sure it is an mpegts file: %d %s", ret, input); } if (av_find_stream_info(ic) < 0) { rb_raise(rb_eException, "Could not read stream information"); } ofmt = av_guess_format("mpegts", NULL, NULL); if (!ofmt) { rb_raise(rb_eException, "Could not find MPEG-TS muxer"); } oc = avformat_alloc_context(); if (!oc) { rb_raise(rb_eException, "Could not allocated output context"); } oc->oformat = ofmt; ic->flags |= AVFMT_FLAG_IGNDTS; video_index = -1; audio_index = -1; for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) { switch (ic->streams[i]->codec->codec_type) { case CODEC_TYPE_VIDEO: video_index = i; ic->streams[i]->discard = AVDISCARD_NONE; video_st = add_output_stream(oc, ic->streams[i]); break; case CODEC_TYPE_AUDIO: audio_index = i; ic->streams[i]->discard = AVDISCARD_NONE; audio_st = add_output_stream(oc, ic->streams[i]); break; default: ic->streams[i]->discard = AVDISCARD_ALL; break; } } if(!soundOnly) { soundOnly = (video_st != NULL); } if (av_set_parameters(oc, NULL) < 0) { rb_raise(rb_eException, "Invalid output format parameters"); } dump_format(oc, 0, output_prefix, 1); if (!soundOnly) { if(video_st == NULL) { fprintf(stderr, "video_st is fail\n"); rb_raise(rb_eException, "video_st fail"); exit(1); } if(video_st->codec == NULL) { fprintf(stderr,"codec is fail\n"); rb_raise(rb_eException, "codec fail"); exit(1); } if(video_st->codec->codec_id == NULL) { fprintf(stderr, "codec_id is fail\n"); rb_raise(rb_eException, "codec fail"); exit(1); } codec = avcodec_find_decoder(video_st->codec->codec_id); if (!codec) { rb_raise(rb_eException, "Could not find video decoder, key frames will not be honored"); } if (avcodec_open(video_st->codec, codec) < 0) { rb_raise(rb_eException, "Could not open video decoder, key frames will not be honored"); } if (video_st->codec->ticks_per_frame > 1) { // h264 sets the ticks_per_frame and time_base.den but not time_base.num // since we don't use ticks_per_frame, adjust time_base.num accordingly. video_st->codec->time_base.num *= video_st->codec->ticks_per_frame; } } snprintf(output_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, output_index++); if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) { rb_raise(rb_eException, "Could not open '%s'", output_filename); } if (av_write_header(oc)) { rb_raise(rb_eException, "Could not write mpegts header to first output file"); } //write_index = !write_index_file(index, tmp_index, segment_duration, output_prefix, http_prefix, first_segment, last_segment, 0, max_tsfiles); int64_t initial_audio_pts = -1; int64_t initial_video_pts = -1; double segment_time; do { AVPacket packet; //av_init_packet(&packet); decode_done = av_read_frame(ic, &packet); if (decode_done < 0) { break; } if (av_dup_packet(&packet) < 0) { rb_raise(rb_eException, "Could not duplicate packet"); av_free_packet(&packet); break; } if (!soundOnly) { if (packet.stream_index == video_index) { if (initial_video_pts < 0) initial_video_pts = packet.pts; packet.pts -= initial_video_pts; packet.dts = packet.pts; if (packet.flags & AV_PKT_FLAG_KEY) { segment_time = (double)packet.pts * video_st->time_base.num / video_st->time_base.den; } else { segment_time = prev_segment_time; } } else if (packet.stream_index == audio_index) { if (initial_audio_pts < 0) initial_audio_pts = packet.pts; packet.pts -= initial_audio_pts; packet.dts = packet.pts; segment_time = prev_segment_time; } else { segment_time = prev_segment_time; segment_time = prev_segment_time; } } else { if (packet.stream_index == audio_index) { if (initial_audio_pts < 0) initial_audio_pts = packet.pts; if (packet.flags & AV_PKT_FLAG_KEY) { segment_time = (double)packet.pts * audio_st->time_base.num / audio_st->time_base.den; } else { segment_time = prev_segment_time; } packet.pts -= initial_audio_pts; packet.dts = packet.pts; } else { segment_time = prev_segment_time; segment_time = prev_segment_time; } } if (segment_time - prev_segment_time >= segment_duration) { put_flush_packet(oc->pb); url_fclose(oc->pb); if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) { remove_file = 1; first_segment++; } else { remove_file = 0; } // Create Segment object VALUE seg = rb_obj_alloc(rb_cAvSegment); rb_obj_call_init(seg, 0, 0); rb_iv_set(seg, "@index", INT2FIX(++last_segment)); rb_iv_set(seg, "@duration",INT2FIX((int)floor((segment_time - prev_segment_time)))); rb_iv_set(seg, "@filename", rb_str_new2(output_filename)); rb_ary_push(sArray, seg); if (remove_file) { snprintf(remove_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, first_segment - 1); //snprintf(remove_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, first_segment - 1); remove(remove_filename); } // snprintf(output_filename, strlen(output_prefix) + 15, "%s-%u.ts", output_prefix, output_index++); snprintf(output_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, output_index++); if (url_fopen(&oc->pb, output_filename, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", output_filename); break; } prev_segment_time = segment_time; } ret = av_interleaved_write_frame(oc, &packet); if (ret < 0) { fprintf(stderr, "Warning: Could not write frame of stream\n"); } else if (ret > 0) { fprintf(stderr, "End of stream requested\n"); av_free_packet(&packet); break; } av_free_packet(&packet); } while (!decode_done); av_write_trailer(oc); if (!soundOnly) avcodec_close(video_st->codec); for(i = 0; i < oc->nb_streams; i++) { if(&oc->streams[i]->codec != NULL) av_freep(&oc->streams[i]->codec); if (&oc->streams[i] != NULL) av_freep(&oc->streams[i]); } url_fclose(oc->pb); av_free(oc); if (max_tsfiles && (int)(last_segment - first_segment) >= max_tsfiles - 1) { remove_file = 1; first_segment++; } else { remove_file = 0; } if (remove_file) { snprintf(remove_filename, strlen(output_prefix) + strlen(folder) + 15, "%s/%s-%u.ts", folder, output_prefix, first_segment - 1); remove(remove_filename); } return sArray; }
void VideoStream::OpenStream() { /* now that all the parameters are set, we can open the video codecs and allocate the necessary encode buffers */ if ( ost ) { #if ZM_FFMPEG_SVN AVCodecContext *c = ost->codec; #else AVCodecContext *c = &ost->codec; #endif /* find the video encoder */ AVCodec *codec = avcodec_find_encoder(c->codec_id); if ( !codec ) { Fatal( "codec not found" ); } /* open the codec */ if ( avcodec_open(c, codec) < 0 ) { Fatal( "Could not open codec" ); } /* allocate the encoded raw picture */ opicture = avcodec_alloc_frame(); if ( !opicture ) { Fatal( "Could not allocate opicture" ); } int size = avpicture_get_size( c->pix_fmt, c->width, c->height); uint8_t *opicture_buf = (uint8_t *)malloc(size); if ( !opicture_buf ) { av_free(opicture); Fatal( "Could not allocate opicture" ); } avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, c->width, c->height ); /* if the output format is not RGB24, then a temporary RGB24 picture is needed too. It is then converted to the required output format */ tmp_opicture = NULL; if ( c->pix_fmt != pf ) { tmp_opicture = avcodec_alloc_frame(); if ( !tmp_opicture ) { Fatal( "Could not allocate temporary opicture" ); } int size = avpicture_get_size( pf, c->width, c->height); uint8_t *tmp_opicture_buf = (uint8_t *)malloc(size); if (!tmp_opicture_buf) { av_free( tmp_opicture ); Fatal( "Could not allocate temporary opicture" ); } avpicture_fill( (AVPicture *)tmp_opicture, tmp_opicture_buf, pf, c->width, c->height ); } } /* open the output file, if needed */ if ( !(of->flags & AVFMT_NOFILE) ) { if ( url_fopen(&ofc->pb, filename, URL_WRONLY) < 0 ) { Fatal( "Could not open '%s'", filename ); } } video_outbuf = NULL; if ( !(ofc->oformat->flags & AVFMT_RAWPICTURE) ) { /* allocate output buffer */ /* XXX: API change will be done */ video_outbuf_size = 200000; video_outbuf = (uint8_t *)malloc(video_outbuf_size); } /* write the stream header, if any */ av_write_header(ofc); }
MediaRet MediaRecorder::finish_setup(const char *fname) { if(av_set_parameters(oc, NULL) < 0) { avformat_free_context(oc); oc = NULL; return MRET_ERR_NOCODEC; } if(audio_buf) free(audio_buf); if(audio_buf2) free(audio_buf2); audio_buf2 = NULL; in_audio_buf2 = 0; if(aud_st) { frame_len = aud_st->codec->frame_size * 4; sample_len = soundGetSampleRate() * 4 / 60; switch(aud_st->codec->codec_id) { case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_U16LE: case CODEC_ID_PCM_U16BE: frame_len = sample_len; } audio_buf = (u8 *)malloc(AUDIO_BUF_LEN); if(!audio_buf) { avformat_free_context(oc); oc = NULL; return MRET_ERR_NOMEM; } if(frame_len != sample_len && (frame_len > sample_len || sample_len % frame_len)) { audio_buf2 = (u16 *)malloc(frame_len); if(!audio_buf2) { avformat_free_context(oc); oc = NULL; return MRET_ERR_NOMEM; } } } else audio_buf = NULL; if(video_buf) free(video_buf); if(vid_st) { video_buf = (u8 *)malloc(VIDEO_BUF_LEN); if(!video_buf) { avformat_free_context(oc); oc = NULL; return MRET_ERR_NOMEM; } } else { video_buf = NULL; } if(!(oc->oformat->flags & AVFMT_NOFILE)) { if(avio_open(&oc->pb, fname, URL_WRONLY) < 0) { avformat_free_context(oc); oc = NULL; return MRET_ERR_FERR; } } av_write_header(oc); return MRET_OK; }
static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports) { /* Handle to the output file */ AVFormatContext* of; AVOutputFormat* fmt; char name[256]; const char ** exts; ffmpeg_type = rd->ffcodecdata.type; ffmpeg_codec = rd->ffcodecdata.codec; ffmpeg_audio_codec = rd->ffcodecdata.audio_codec; ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; ffmpeg_gop_size = rd->ffcodecdata.gop_size; ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT; do_init_ffmpeg(); /* Determine the correct filename */ filepath_ffmpeg(name, rd); fprintf(stderr, "Starting output to %s(ffmpeg)...\n" " Using type=%d, codec=%d, audio_codec=%d,\n" " video_bitrate=%d, audio_bitrate=%d,\n" " gop_size=%d, autosplit=%d\n" " render width=%d, render height=%d\n", name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec, ffmpeg_video_bitrate, ffmpeg_audio_bitrate, ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty); exts = get_file_extensions(ffmpeg_type); if (!exts) { BKE_report(reports, RPT_ERROR, "No valid formats found."); return 0; } fmt = av_guess_format(NULL, exts[0], NULL); if (!fmt) { BKE_report(reports, RPT_ERROR, "No valid formats found."); return 0; } of = avformat_alloc_context(); if (!of) { BKE_report(reports, RPT_ERROR, "Error opening output file"); return 0; } of->oformat = fmt; of->packet_size= rd->ffcodecdata.mux_packet_size; if (ffmpeg_audio_codec != CODEC_ID_NONE) { of->mux_rate = rd->ffcodecdata.mux_rate; } else { of->mux_rate = 0; } of->preload = (int)(0.5*AV_TIME_BASE); of->max_delay = (int)(0.7*AV_TIME_BASE); fmt->audio_codec = ffmpeg_audio_codec; BLI_snprintf(of->filename, sizeof(of->filename), "%s", name); /* set the codec to the user's selection */ switch(ffmpeg_type) { case FFMPEG_AVI: case FFMPEG_MOV: case FFMPEG_MKV: fmt->video_codec = ffmpeg_codec; break; case FFMPEG_OGG: fmt->video_codec = CODEC_ID_THEORA; break; case FFMPEG_DV: fmt->video_codec = CODEC_ID_DVVIDEO; break; case FFMPEG_MPEG1: fmt->video_codec = CODEC_ID_MPEG1VIDEO; break; case FFMPEG_MPEG2: fmt->video_codec = CODEC_ID_MPEG2VIDEO; break; case FFMPEG_H264: fmt->video_codec = CODEC_ID_H264; break; case FFMPEG_XVID: fmt->video_codec = CODEC_ID_MPEG4; break; case FFMPEG_FLV: fmt->video_codec = CODEC_ID_FLV1; break; case FFMPEG_MP3: fmt->audio_codec = CODEC_ID_MP3; case FFMPEG_WAV: fmt->video_codec = CODEC_ID_NONE; break; case FFMPEG_MPEG4: default: fmt->video_codec = CODEC_ID_MPEG4; break; } if (fmt->video_codec == CODEC_ID_DVVIDEO) { if (rectx != 720) { BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!"); return 0; } if (rd->frs_sec != 25 && recty != 480) { BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!"); return 0; } if (rd->frs_sec == 25 && recty != 576) { BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!"); return 0; } } if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) { BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); return 0; } } if (fmt->video_codec != CODEC_ID_NONE) { video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty); printf("alloc video stream %p\n", video_stream); if (!video_stream) { BKE_report(reports, RPT_ERROR, "Error initializing video stream."); return 0; } } if (ffmpeg_audio_codec != CODEC_ID_NONE) { audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of); if (!audio_stream) { BKE_report(reports, RPT_ERROR, "Error initializing audio stream."); return 0; } } if (av_set_parameters(of, NULL) < 0) { BKE_report(reports, RPT_ERROR, "Error setting output parameters."); return 0; } if (!(fmt->flags & AVFMT_NOFILE)) { if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) { BKE_report(reports, RPT_ERROR, "Could not open file for writing."); return 0; } } if (av_write_header(of) < 0) { BKE_report(reports, RPT_ERROR, "Could not initialize streams. Probably unsupported codec combination."); return 0; } outfile = of; av_dump_format(of, 0, name, 1); return 1; }
void VideoWriterThread::open() { av_register_all(); // TODO: make sure this is only done once. // av_log_set_level(AV_LOG_DEBUG); #if LIBAVFORMAT_VERSION_MAJOR > 52 m_pOutputFormat = av_guess_format(0, m_sFilename.c_str(), 0); #else m_pOutputFormat = guess_format(0, m_sFilename.c_str(), 0); #endif m_pOutputFormat->video_codec = CODEC_ID_MJPEG; #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 24, 0) m_pOutputFormatContext = avformat_alloc_context(); #else m_pOutputFormatContext = av_alloc_format_context(); #endif m_pOutputFormatContext->oformat = m_pOutputFormat; strncpy(m_pOutputFormatContext->filename, m_sFilename.c_str(), sizeof(m_pOutputFormatContext->filename)); if (m_pOutputFormat->video_codec != CODEC_ID_NONE) { setupVideoStream(); } #if LIBAVFORMAT_VERSION_MAJOR < 52 av_set_parameters(m_pOutputFormatContext, NULL); #endif float muxMaxDelay = 0.7; m_pOutputFormatContext->max_delay = int(muxMaxDelay * AV_TIME_BASE); // av_dump_format(m_pOutputFormatContext, 0, m_sFilename.c_str(), 1); openVideoCodec(); m_pVideoBuffer = NULL; if (!(m_pOutputFormatContext->oformat->flags & AVFMT_RAWPICTURE)) { m_pVideoBuffer = (unsigned char*)(av_malloc(VIDEO_BUFFER_SIZE)); } if (!(m_pOutputFormat->flags & AVFMT_NOFILE)) { #if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(53, 8, 0) int retVal = avio_open(&m_pOutputFormatContext->pb, m_sFilename.c_str(), URL_WRONLY); #else int retVal = url_fopen(&m_pOutputFormatContext->pb, m_sFilename.c_str(), URL_WRONLY); #endif if (retVal < 0) { throw Exception(AVG_ERR_VIDEO_INIT_FAILED, string("Could not open output file: '") + m_sFilename + "'"); } } m_pFrameConversionContext = sws_getContext(m_Size.x, m_Size.y, ::PIX_FMT_RGB32, m_Size.x, m_Size.y, STREAM_PIXEL_FORMAT, SWS_BILINEAR, NULL, NULL, NULL); m_pConvertedFrame = createFrame(STREAM_PIXEL_FORMAT, m_Size); #if LIBAVFORMAT_VERSION_MAJOR > 52 avformat_write_header(m_pOutputFormatContext, 0); #else av_write_header(m_pOutputFormatContext); #endif }
static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data) { GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) user_data; GSList *collected; GstFFMpegMuxPad *best_pad; GstClockTime best_time; const GstTagList *tags; /* open "file" (gstreamer protocol to next element) */ if (!ffmpegmux->opened) { int open_flags = URL_WRONLY; /* we do need all streams to have started capsnego, * or things will go horribly wrong */ for (collected = ffmpegmux->collect->data; collected; collected = g_slist_next (collected)) { GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data; AVStream *st = ffmpegmux->context->streams[collect_pad->padnum]; /* check whether the pad has successfully completed capsnego */ if (st->codec->codec_id == CODEC_ID_NONE) { GST_ELEMENT_ERROR (ffmpegmux, CORE, NEGOTIATION, (NULL), ("no caps set on stream %d (%s)", collect_pad->padnum, (st->codec->codec_type == CODEC_TYPE_VIDEO) ? "video" : "audio")); return GST_FLOW_ERROR; } /* set framerate for audio */ if (st->codec->codec_type == CODEC_TYPE_AUDIO) { switch (st->codec->codec_id) { case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_U16LE: case CODEC_ID_PCM_U16BE: case CODEC_ID_PCM_S8: case CODEC_ID_PCM_U8: st->codec->frame_size = 1; break; default: { GstBuffer *buffer; /* FIXME : This doesn't work for RAW AUDIO... * in fact I'm wondering if it even works for any kind of audio... */ buffer = gst_collect_pads_peek (ffmpegmux->collect, (GstCollectData *) collect_pad); if (buffer) { st->codec->frame_size = st->codec->sample_rate * GST_BUFFER_DURATION (buffer) / GST_SECOND; gst_buffer_unref (buffer); } } } } } /* tags */ tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ffmpegmux)); if (tags) { gint i; gchar *s; /* get the interesting ones */ if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)) { strncpy (ffmpegmux->context->title, s, sizeof (ffmpegmux->context->title)); } if (gst_tag_list_get_string (tags, GST_TAG_ARTIST, &s)) { strncpy (ffmpegmux->context->author, s, sizeof (ffmpegmux->context->author)); } if (gst_tag_list_get_string (tags, GST_TAG_COPYRIGHT, &s)) { strncpy (ffmpegmux->context->copyright, s, sizeof (ffmpegmux->context->copyright)); } if (gst_tag_list_get_string (tags, GST_TAG_COMMENT, &s)) { strncpy (ffmpegmux->context->comment, s, sizeof (ffmpegmux->context->comment)); } if (gst_tag_list_get_string (tags, GST_TAG_ALBUM, &s)) { strncpy (ffmpegmux->context->album, s, sizeof (ffmpegmux->context->album)); } if (gst_tag_list_get_string (tags, GST_TAG_GENRE, &s)) { strncpy (ffmpegmux->context->genre, s, sizeof (ffmpegmux->context->genre)); } if (gst_tag_list_get_int (tags, GST_TAG_TRACK_NUMBER, &i)) { ffmpegmux->context->track = i; } } /* set the streamheader flag for gstffmpegprotocol if codec supports it */ if (!strcmp (ffmpegmux->context->oformat->name, "flv")) { open_flags |= GST_FFMPEG_URL_STREAMHEADER; } if (url_fopen (&ffmpegmux->context->pb, ffmpegmux->context->filename, open_flags) < 0) { GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, TOO_LAZY, (NULL), ("Failed to open stream context in ffmux")); return GST_FLOW_ERROR; } if (av_set_parameters (ffmpegmux->context, NULL) < 0) { GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, INIT, (NULL), ("Failed to initialize muxer")); return GST_FLOW_ERROR; } /* now open the mux format */ if (av_write_header (ffmpegmux->context) < 0) { GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, SETTINGS, (NULL), ("Failed to write file header - check codec settings")); return GST_FLOW_ERROR; } /* we're now opened */ ffmpegmux->opened = TRUE; /* flush the header so it will be used as streamheader */ put_flush_packet (ffmpegmux->context->pb); } /* take the one with earliest timestamp, * and push it forward */ best_pad = NULL; best_time = GST_CLOCK_TIME_NONE; for (collected = ffmpegmux->collect->data; collected; collected = g_slist_next (collected)) { GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data; GstBuffer *buffer = gst_collect_pads_peek (ffmpegmux->collect, (GstCollectData *) collect_pad); /* if there's no buffer, just continue */ if (buffer == NULL) { continue; } /* if we have no buffer yet, just use the first one */ if (best_pad == NULL) { best_pad = collect_pad; best_time = GST_BUFFER_TIMESTAMP (buffer); goto next_pad; } /* if we do have one, only use this one if it's older */ if (GST_BUFFER_TIMESTAMP (buffer) < best_time) { best_time = GST_BUFFER_TIMESTAMP (buffer); best_pad = collect_pad; } next_pad: gst_buffer_unref (buffer); /* Mux buffers with invalid timestamp first */ if (!GST_CLOCK_TIME_IS_VALID (best_time)) break; } /* now handle the buffer, or signal EOS if we have * no buffers left */ if (best_pad != NULL) { GstBuffer *buf; AVPacket pkt; gboolean need_free = FALSE; /* push out current buffer */ buf = gst_collect_pads_pop (ffmpegmux->collect, (GstCollectData *) best_pad); ffmpegmux->context->streams[best_pad->padnum]->codec->frame_number++; /* set time */ pkt.pts = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_TIMESTAMP (buf), ffmpegmux->context->streams[best_pad->padnum]->time_base); pkt.dts = pkt.pts; if (strcmp (ffmpegmux->context->oformat->name, "gif") == 0) { AVStream *st = ffmpegmux->context->streams[best_pad->padnum]; AVPicture src, dst; need_free = TRUE; pkt.size = st->codec->width * st->codec->height * 3; pkt.data = g_malloc (pkt.size); dst.data[0] = pkt.data; dst.data[1] = NULL; dst.data[2] = NULL; dst.linesize[0] = st->codec->width * 3; gst_ffmpeg_avpicture_fill (&src, GST_BUFFER_DATA (buf), PIX_FMT_RGB24, st->codec->width, st->codec->height); av_picture_copy (&dst, &src, PIX_FMT_RGB24, st->codec->width, st->codec->height); } else { pkt.data = GST_BUFFER_DATA (buf); pkt.size = GST_BUFFER_SIZE (buf); } pkt.stream_index = best_pad->padnum; pkt.flags = 0; if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) pkt.flags |= PKT_FLAG_KEY; if (GST_BUFFER_DURATION_IS_VALID (buf)) pkt.duration = gst_ffmpeg_time_gst_to_ff (GST_BUFFER_DURATION (buf), ffmpegmux->context->streams[best_pad->padnum]->time_base); else pkt.duration = 0; av_write_frame (ffmpegmux->context, &pkt); gst_buffer_unref (buf); if (need_free) g_free (pkt.data); } else { /* close down */ av_write_trailer (ffmpegmux->context); ffmpegmux->opened = FALSE; put_flush_packet (ffmpegmux->context->pb); url_fclose (ffmpegmux->context->pb); gst_pad_push_event (ffmpegmux->srcpad, gst_event_new_eos ()); return GST_FLOW_UNEXPECTED; } return GST_FLOW_OK; }
void VideoStream::OpenStream( ) { int avRet; /* now that all the parameters are set, we can open the video codecs and allocate the necessary encode buffers */ if ( ost ) { AVCodecContext *c = ost->codec; /* open the codec */ #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0) if ( (avRet = avcodec_open( c, codec )) < 0 ) #else if ( (avRet = avcodec_open2( c, codec, 0 )) < 0 ) #endif { Fatal( "Could not open codec. Error code %d \"%s\"", avRet, av_err2str( avRet ) ); } Debug( 1, "Opened codec" ); /* allocate the encoded raw picture */ opicture = avcodec_alloc_frame( ); if ( !opicture ) { Panic( "Could not allocate opicture" ); } int size = avpicture_get_size( c->pix_fmt, c->width, c->height ); uint8_t *opicture_buf = (uint8_t *)av_malloc( size ); if ( !opicture_buf ) { av_free( opicture ); Panic( "Could not allocate opicture_buf" ); } avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, c->width, c->height ); /* if the output format is not identical to the input format, then a temporary picture is needed too. It is then converted to the required output format */ tmp_opicture = NULL; if ( c->pix_fmt != pf ) { tmp_opicture = avcodec_alloc_frame( ); if ( !tmp_opicture ) { Panic( "Could not allocate tmp_opicture" ); } int size = avpicture_get_size( pf, c->width, c->height ); uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size ); if ( !tmp_opicture_buf ) { av_free( tmp_opicture ); Panic( "Could not allocate tmp_opicture_buf" ); } avpicture_fill( (AVPicture *)tmp_opicture, tmp_opicture_buf, pf, c->width, c->height ); } } /* open the output file, if needed */ if ( !(of->flags & AVFMT_NOFILE) ) { int ret; #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 14, 0) ret = avio_open2( &ofc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL ); #elif LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 102, 0) ret = avio_open( &ofc->pb, filename, AVIO_FLAG_WRITE ); #else ret = url_fopen( &ofc->pb, filename, AVIO_FLAG_WRITE ); #endif if ( ret < 0 ) { Fatal( "Could not open '%s'", filename ); } Debug( 1, "Opened output \"%s\"", filename ); } else { Fatal( "of->flags & AVFMT_NOFILE" ); } video_outbuf = NULL; if ( !(of->flags & AVFMT_RAWPICTURE) ) { /* allocate output buffer */ /* XXX: API change will be done */ // TODO: Make buffer dynamic. video_outbuf_size = 4000000; video_outbuf = (uint8_t *)malloc( video_outbuf_size ); } #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 100, 1) av_dump_format(ofc, 0, filename, 1); #else dump_format(ofc, 0, filename, 1); #endif #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0) int ret = av_write_header( ofc ); #else int ret = avformat_write_header( ofc, NULL ); #endif if ( ret < 0 ) { Fatal( "?_write_header failed with error %d \"%s\"", ret, av_err2str( ret ) ); } }
int ff_mov_init_hinting(AVFormatContext *s, int index, int src_index) { MOVMuxContext *mov = s->priv_data; MOVTrack *track = &mov->tracks[index]; MOVTrack *src_track = &mov->tracks[src_index]; AVStream *src_st = s->streams[src_index]; int ret = AVERROR(ENOMEM); AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); track->tag = MKTAG('r','t','p',' '); track->src_track = src_index; if (!rtp_format) { ret = AVERROR(ENOENT); goto fail; } track->enc = avcodec_alloc_context(); if (!track->enc) goto fail; track->enc->codec_type = AVMEDIA_TYPE_DATA; track->enc->codec_tag = track->tag; track->rtp_ctx = avformat_alloc_context(); if (!track->rtp_ctx) goto fail; track->rtp_ctx->oformat = rtp_format; if (!av_new_stream(track->rtp_ctx, 0)) goto fail; /* Copy stream parameters */ track->rtp_ctx->streams[0]->sample_aspect_ratio = src_st->sample_aspect_ratio; /* Remove the allocated codec context, link to the original one * instead, to give the rtp muxer access to codec parameters. */ av_free(track->rtp_ctx->streams[0]->codec); track->rtp_ctx->streams[0]->codec = src_st->codec; if ((ret = url_open_dyn_packet_buf(&track->rtp_ctx->pb, RTP_MAX_PACKET_SIZE)) < 0) goto fail; ret = av_write_header(track->rtp_ctx); if (ret) goto fail; /* Copy the RTP AVStream timebase back to the hint AVStream */ track->timescale = track->rtp_ctx->streams[0]->time_base.den; /* Mark the hinted track that packets written to it should be * sent to this track for hinting. */ src_track->hint_track = index; return 0; fail: av_log(s, AV_LOG_WARNING, "Unable to initialize hinting of stream %d\n", src_index); if (track->rtp_ctx && track->rtp_ctx->pb) { uint8_t *buf; url_close_dyn_buf(track->rtp_ctx->pb, &buf); av_free(buf); } if (track->rtp_ctx && track->rtp_ctx->streams[0]) { av_metadata_free(&track->rtp_ctx->streams[0]->metadata); av_free(track->rtp_ctx->streams[0]); } if (track->rtp_ctx) { av_metadata_free(&track->rtp_ctx->metadata); av_free(track->rtp_ctx->priv_data); av_freep(&track->rtp_ctx); } av_freep(&track->enc); /* Set a default timescale, to avoid crashes in dump_format */ track->timescale = 90000; return ret; }
static struct proxy_output_ctx * alloc_proxy_output_ffmpeg( struct anim * anim, AVStream * st, int proxy_size, int width, int height, int quality) { struct proxy_output_ctx * rv = MEM_callocN( sizeof(struct proxy_output_ctx), "alloc_proxy_output"); char fname[FILE_MAXDIR+FILE_MAXFILE]; // JPEG requires this width = round_up(width, 8); height = round_up(height, 8); rv->proxy_size = proxy_size; rv->anim = anim; get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE); BLI_make_existing_file(fname); rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); BLI_snprintf(rv->of->filename, sizeof(rv->of->filename), "%s", fname); fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename); rv->st = av_new_stream(rv->of, 0); rv->c = rv->st->codec; rv->c->codec_type = AVMEDIA_TYPE_VIDEO; rv->c->codec_id = CODEC_ID_MJPEG; rv->c->width = width; rv->c->height = height; rv->of->oformat->video_codec = rv->c->codec_id; rv->codec = avcodec_find_encoder(rv->c->codec_id); if (!rv->codec) { fprintf(stderr, "No ffmpeg MJPEG encoder available? " "Proxy not built!\n"); av_free(rv->of); return NULL; } if (rv->codec->pix_fmts) { rv->c->pix_fmt = rv->codec->pix_fmts[0]; } else { rv->c->pix_fmt = PIX_FMT_YUVJ420P; } rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->codec->sample_aspect_ratio; rv->c->time_base.den = 25; rv->c->time_base.num = 1; rv->st->time_base = rv->c->time_base; if (rv->of->flags & AVFMT_GLOBALHEADER) { rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER; } if (av_set_parameters(rv->of, NULL) < 0) { fprintf(stderr, "Couldn't set output parameters? " "Proxy not built!\n"); av_free(rv->of); return 0; } if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Couldn't open outputfile! " "Proxy not built!\n"); av_free(rv->of); return 0; } avcodec_open(rv->c, rv->codec); rv->video_buffersize = 2000000; rv->video_buffer = (uint8_t*)MEM_mallocN( rv->video_buffersize, "FFMPEG video buffer"); rv->orig_height = st->codec->height; if (st->codec->width != width || st->codec->height != height || st->codec->pix_fmt != rv->c->pix_fmt) { rv->frame = avcodec_alloc_frame(); avpicture_fill((AVPicture*) rv->frame, MEM_mallocN(avpicture_get_size( rv->c->pix_fmt, round_up(width, 16), height), "alloc proxy output frame"), rv->c->pix_fmt, round_up(width, 16), height); rv->sws_ctx = sws_getContext( st->codec->width, st->codec->height, st->codec->pix_fmt, width, height, rv->c->pix_fmt, SWS_FAST_BILINEAR | SWS_PRINT_INFO, NULL, NULL, NULL); } av_write_header(rv->of); return rv; }
uint8_t lavMuxer::open(const char *filename,uint32_t inbitrate, ADM_MUXER_TYPE type, aviInfo *info, uint32_t videoExtraDataSize, uint8_t *videoExtraData, WAVHeader *audioheader, uint32_t audioextraSize,uint8_t *audioextraData) { AVCodecContext *c; _type=type; _fps1000=info->fps1000; switch(_type) { case MUXER_TS: fmt = av_guess_format("mpegts", NULL, NULL); break; case MUXER_DVD: fmt = av_guess_format("dvd", NULL, NULL); break; case MUXER_VCD: fmt = av_guess_format("vcd", NULL, NULL); break; case MUXER_SVCD: fmt = av_guess_format("svcd", NULL, NULL); break; case MUXER_MP4: fmt = av_guess_format("mp4", NULL, NULL); break; case MUXER_PSP: fmt = av_guess_format("psp", NULL, NULL); break; case MUXER_FLV: fmt = av_guess_format("flv", NULL, NULL); break; case MUXER_MATROSKA: fmt = av_guess_format("matroska", NULL, NULL); break; default: fmt=NULL; } if (!fmt) { printf("Lav:Cannot guess format\n"); ADM_assert(0); return 0; } oc = avformat_alloc_context(); if (!oc) { printf("Lav:Cannot allocate context\n"); return 0; } oc->oformat = fmt; snprintf(oc->filename,1000,"file://%s",filename); // Video //________ video_st = av_new_stream(oc, 0); if (!video_st) { printf("Lav: new stream failed\n"); return 0; } c = video_st->codec; c->gop_size=15; c->max_b_frames=2; c->has_b_frames=1; switch(_type) { case MUXER_FLV: c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); if(fourCC::check(info->fcc,(uint8_t *)"FLV1")) { c->codec_id=CODEC_ID_FLV1; c->codec->name=ADM_strdup("FLV1"); }else { if(isVP6Compatible(info->fcc)) { c->codec_id=CODEC_ID_VP6F; c->codec->name=ADM_strdup("VP6F"); } else ADM_assert(0); } break; case MUXER_MATROSKA: strcpy(oc->title,"Avidemux"); strcpy(oc->author,"Avidemux"); if(isMpeg4Compatible(info->fcc)) { c->codec_id = CODEC_ID_MPEG4; }else { if(isH264Compatible(info->fcc)) { c->has_b_frames=2; // let muxer know we may have bpyramid c->codec_id = CODEC_ID_H264; c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); c->codec->name=ADM_strdup("H264"); } else { if(!ADM_4cc_to_lavcodec((const char *)&(info->fcc),&(c->codec_id))) { printf("[lavFormat] Cannot map this\n"); return 0; } } } if(videoExtraDataSize) { c->extradata=videoExtraData; c->extradata_size= videoExtraDataSize; } break; case MUXER_MP4: case MUXER_PSP: { // probably a memeleak here char *foo=ADM_strdup(filename); strcpy(oc->title,ADM_GetFileName(foo)); strcpy(oc->author,"Avidemux"); if(isMpeg4Compatible(info->fcc)) { c->codec_id = CODEC_ID_MPEG4; }else { if(isH264Compatible(info->fcc)) { c->has_b_frames=2; // let muxer know we may have bpyramid c->codec_id = CODEC_ID_H264; c->codec=new AVCodec; memset(c->codec,0,sizeof(AVCodec)); c->codec->name=ADM_strdup("H264"); } else { if(isDVCompatible(info->fcc)) { c->codec_id = CODEC_ID_DVVIDEO; }else { if(fourCC::check(info->fcc,(uint8_t *)"H263")) { c->codec_id=CODEC_ID_H263; }else{ c->codec_id = CODEC_ID_MPEG4; // Default value printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); printf("Ooops, cant mux that...\n"); } } } } if(videoExtraDataSize) { c->extradata=videoExtraData; c->extradata_size= videoExtraDataSize; } if(MUXER_PSP==_type) { c->rc_buffer_size=0; //8*1024*224; c->rc_max_rate=0; //768*1000; c->rc_min_rate=0; c->bit_rate=768*1000; } else { c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; } } break; case MUXER_TS: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_DVD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*224; c->rc_max_rate=9500*1000; c->rc_min_rate=0; if(!inbitrate) c->bit_rate=9000*1000; else c->bit_rate=inbitrate; break; case MUXER_VCD: c->codec_id = CODEC_ID_MPEG1VIDEO; c->rc_buffer_size=8*1024*40; c->rc_max_rate=1152*1000; c->rc_min_rate=1152*1000; c->bit_rate=1152*1000; break; case MUXER_SVCD: c->codec_id = CODEC_ID_MPEG2VIDEO; c->rc_buffer_size=8*1024*112; c->rc_max_rate=2500*1000; c->rc_min_rate=0*1000; if(!inbitrate) c->bit_rate=2040*1000; else c->bit_rate=inbitrate; break; default: ADM_assert(0); } c->codec_type = CODEC_TYPE_VIDEO; c->flags=CODEC_FLAG_QSCALE; c->width = info->width; c->height = info->height; AVRational fps25=(AVRational){1001,25025}; AVRational fps24=(AVRational){1001,24000}; AVRational fps30= (AVRational){1001,30000}; AVRational fpsfree= (AVRational){1000,_fps1000}; switch(_fps1000) { case 25000: { c->time_base= fps25; break; } case 23976: if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV || _type==MUXER_MATROSKA) { c->time_base= fps24; //(AVRational){1001,24000}; break; } case 29970: c->time_base=fps30; break; default: { if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV || _type==MUXER_MATROSKA) { c->time_base=fpsfree;// (AVRational){1000,_fps1000}; break; } else { GUI_Error_HIG(QT_TR_NOOP("Incompatible frame rate"), NULL); return 0; } } break; } // Audio //________ if(audioheader) { audio_st = av_new_stream(oc, 1); if (!audio_st) { printf("Lav: new stream failed\n"); return 0; } c = audio_st->codec; c->frame_size=1024; //For AAC mainly, sample per frame printf("[LavFormat] Bitrate %u\n",(audioheader->byterate*8)/1000); _audioFq=c->sample_rate = audioheader->frequency; #if 0 if(_type== MUXER_PSP && audioheader->encoding==WAV_AAC) { _audioFq=c->sample_rate = audioheader->frequency/2; //_audioFq*=2; // SBR } #endif switch(audioheader->encoding) { case WAV_AC3: c->codec_id = CODEC_ID_AC3;c->frame_size=6*256;break; case WAV_MP2: c->codec_id = CODEC_ID_MP2;break; case WAV_MP3: #warning FIXME : Probe deeper c->frame_size=1152; c->codec_id = CODEC_ID_MP3; break; case WAV_PCM: // One chunk is 10 ms (1/100 of fq) c->frame_size=4; c->codec_id = CODEC_ID_PCM_S16LE;break; case WAV_AAC: c->extradata=audioextraData; c->extradata_size= audioextraSize; c->codec_id = CODEC_ID_AAC; break; default: if(_type==MUXER_MATROSKA) { if(ADM_WaveTag_to_lavcodec(audioheader->encoding, &(c->codec_id))) { if(audioextraData) { c->extradata=audioextraData; c->extradata_size= audioextraSize; } // Put a dummy time increment c->time_base= fps25; break; } } printf("Cant mux that ! audio\n"); printf("Cant mux that ! audio\n"); c->codec_id = CODEC_ID_MP2; return 0; break; } c->codec_type = CODEC_TYPE_AUDIO; c->bit_rate = audioheader->byterate*8; c->rc_buffer_size=(c->bit_rate/(2*8)); // 500 ms worth c->channels = audioheader->channels; _audioByterate=audioheader->byterate; } // /audio //---------------------- switch(_type) { case MUXER_FLV: case MUXER_PSP: case MUXER_MP4: case MUXER_MATROSKA: oc->mux_rate=10080*1000; // Needed ? break; case MUXER_TS: oc->mux_rate=10080*1000; break; case MUXER_DVD: oc->packet_size=2048; oc->mux_rate=10080*1000; break; case MUXER_VCD: oc->packet_size=2324; oc->mux_rate=2352 * 75 * 8; break; case MUXER_SVCD: oc->packet_size=2324; oc->mux_rate=2*2352 * 75 * 8; // ? break; default: ADM_assert(0); } oc->preload=AV_TIME_BASE/10; // 100 ms preloading oc->max_delay=200*1000; // 500 ms if (av_set_parameters(oc, NULL) < 0) { printf("Lav: set param failed \n"); return 0; } if (url_fopen(&(oc->pb), filename, URL_WRONLY) < 0) { printf("Lav: Failed to open file :%s\n",filename); return 0; } ADM_assert(av_write_header(oc)>=0); dump_format(oc, 0, filename, 1); printf("lavformat mpeg muxer initialized\n"); _running=1; one=(1000*1000*1000)/_fps1000; _curDTS=one; return 1; }
static int artwork_rescale(AVFormatContext *src_ctx, int s, int out_w, int out_h, int format, struct evbuffer *evbuf) { uint8_t *buf; uint8_t *outbuf; AVCodecContext *src; AVFormatContext *dst_ctx; AVCodecContext *dst; AVOutputFormat *dst_fmt; AVStream *dst_st; AVCodec *img_decoder; AVCodec *img_encoder; int64_t pix_fmt_mask; const enum PixelFormat *pix_fmts; AVFrame *i_frame; AVFrame *o_frame; struct SwsContext *swsctx; AVPacket pkt; int have_frame; int outbuf_len; int ret; src = src_ctx->streams[s]->codec; img_decoder = avcodec_find_decoder(src->codec_id); if (!img_decoder) { DPRINTF(E_LOG, L_ART, "No suitable decoder found for artwork %s\n", src_ctx->filename); return -1; } #if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 6) ret = avcodec_open2(src, img_decoder, NULL); #else ret = avcodec_open(src, img_decoder); #endif if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not open codec for decoding: %s\n", strerror(AVUNERROR(ret))); return -1; } /* Set up output */ #if LIBAVFORMAT_VERSION_MAJOR >= 53 || (LIBAVFORMAT_VERSION_MAJOR == 52 && LIBAVFORMAT_VERSION_MINOR >= 45) /* FFmpeg 0.6 */ dst_fmt = av_guess_format("image2", NULL, NULL); #else dst_fmt = guess_format("image2", NULL, NULL); #endif if (!dst_fmt) { DPRINTF(E_LOG, L_ART, "ffmpeg image2 muxer not available\n"); ret = -1; goto out_close_src; } dst_fmt->video_codec = CODEC_ID_NONE; /* Try to keep same codec if possible */ if ((src->codec_id == CODEC_ID_PNG) && (format & ART_CAN_PNG)) dst_fmt->video_codec = CODEC_ID_PNG; else if ((src->codec_id == CODEC_ID_MJPEG) && (format & ART_CAN_JPEG)) dst_fmt->video_codec = CODEC_ID_MJPEG; /* If not possible, select new codec */ if (dst_fmt->video_codec == CODEC_ID_NONE) { if (format & ART_CAN_PNG) dst_fmt->video_codec = CODEC_ID_PNG; else if (format & ART_CAN_JPEG) dst_fmt->video_codec = CODEC_ID_MJPEG; } img_encoder = avcodec_find_encoder(dst_fmt->video_codec); if (!img_encoder) { DPRINTF(E_LOG, L_ART, "No suitable encoder found for codec ID %d\n", dst_fmt->video_codec); ret = -1; goto out_close_src; } dst_ctx = avformat_alloc_context(); if (!dst_ctx) { DPRINTF(E_LOG, L_ART, "Out of memory for format context\n"); ret = -1; goto out_close_src; } dst_ctx->oformat = dst_fmt; #if LIBAVFORMAT_VERSION_MAJOR >= 53 dst_fmt->flags &= ~AVFMT_NOFILE; #else ret = snprintf(dst_ctx->filename, sizeof(dst_ctx->filename), "evbuffer:%p", evbuf); if ((ret < 0) || (ret >= sizeof(dst_ctx->filename))) { DPRINTF(E_LOG, L_ART, "Output artwork URL too long\n"); ret = -1; goto out_free_dst_ctx; } #endif #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 21) dst_st = avformat_new_stream(dst_ctx, NULL); #else dst_st = av_new_stream(dst_ctx, 0); #endif if (!dst_st) { DPRINTF(E_LOG, L_ART, "Out of memory for new output stream\n"); ret = -1; goto out_free_dst_ctx; } dst = dst_st->codec; #if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 35) avcodec_get_context_defaults3(dst, NULL); #else avcodec_get_context_defaults2(dst, AVMEDIA_TYPE_VIDEO); #endif if (dst_fmt->flags & AVFMT_GLOBALHEADER) dst->flags |= CODEC_FLAG_GLOBAL_HEADER; dst->codec_id = dst_fmt->video_codec; #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 64) dst->codec_type = AVMEDIA_TYPE_VIDEO; #else dst->codec_type = CODEC_TYPE_VIDEO; #endif pix_fmt_mask = 0; pix_fmts = img_encoder->pix_fmts; while (pix_fmts && (*pix_fmts != -1)) { pix_fmt_mask |= (1 << *pix_fmts); pix_fmts++; } dst->pix_fmt = avcodec_find_best_pix_fmt(pix_fmt_mask, src->pix_fmt, 1, NULL); if (dst->pix_fmt < 0) { DPRINTF(E_LOG, L_ART, "Could not determine best pixel format\n"); ret = -1; goto out_free_dst_ctx; } DPRINTF(E_DBG, L_ART, "Selected pixel format: %d\n", dst->pix_fmt); dst->time_base.num = 1; dst->time_base.den = 25; dst->width = out_w; dst->height = out_h; #if LIBAVFORMAT_VERSION_MAJOR <= 52 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR <= 1) ret = av_set_parameters(dst_ctx, NULL); if (ret < 0) { DPRINTF(E_LOG, L_ART, "Invalid parameters for artwork output: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_free_dst_ctx; } #endif /* Open encoder */ #if LIBAVCODEC_VERSION_MAJOR >= 54 || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR >= 6) ret = avcodec_open2(dst, img_encoder, NULL); #else ret = avcodec_open(dst, img_encoder); #endif if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not open codec for encoding: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_free_dst_ctx; } i_frame = avcodec_alloc_frame(); o_frame = avcodec_alloc_frame(); if (!i_frame || !o_frame) { DPRINTF(E_LOG, L_ART, "Could not allocate input/output frame\n"); ret = -1; goto out_free_frames; } ret = avpicture_get_size(dst->pix_fmt, src->width, src->height); DPRINTF(E_DBG, L_ART, "Artwork buffer size: %d\n", ret); buf = (uint8_t *)av_malloc(ret); if (!buf) { DPRINTF(E_LOG, L_ART, "Out of memory for artwork buffer\n"); ret = -1; goto out_free_frames; } avpicture_fill((AVPicture *)o_frame, buf, dst->pix_fmt, src->width, src->height); swsctx = sws_getContext(src->width, src->height, src->pix_fmt, dst->width, dst->height, dst->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); if (!swsctx) { DPRINTF(E_LOG, L_ART, "Could not get SWS context\n"); ret = -1; goto out_free_buf; } /* Get frame */ have_frame = 0; while (av_read_frame(src_ctx, &pkt) == 0) { if (pkt.stream_index != s) { av_free_packet(&pkt); continue; } #if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 32) /* FFmpeg 0.6 */ avcodec_decode_video2(src, i_frame, &have_frame, &pkt); #else avcodec_decode_video(src, i_frame, &have_frame, pkt.data, pkt.size); #endif break; } if (!have_frame) { DPRINTF(E_LOG, L_ART, "Could not decode artwork\n"); av_free_packet(&pkt); sws_freeContext(swsctx); ret = -1; goto out_free_buf; } /* Scale */ #if LIBSWSCALE_VERSION_MAJOR >= 1 || (LIBSWSCALE_VERSION_MAJOR == 0 && LIBSWSCALE_VERSION_MINOR >= 9) /* FFmpeg 0.6, libav 0.6+ */ sws_scale(swsctx, (const uint8_t * const *)i_frame->data, i_frame->linesize, 0, src->height, o_frame->data, o_frame->linesize); #else sws_scale(swsctx, i_frame->data, i_frame->linesize, 0, src->height, o_frame->data, o_frame->linesize); #endif sws_freeContext(swsctx); av_free_packet(&pkt); /* Open output file */ #if LIBAVFORMAT_VERSION_MAJOR >= 53 dst_ctx->pb = avio_evbuffer_open(evbuf); #else ret = url_fopen(&dst_ctx->pb, dst_ctx->filename, URL_WRONLY); #endif if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not open artwork destination buffer\n"); ret = -1; goto out_free_buf; } /* Encode frame */ outbuf_len = dst->width * dst->height * 3; if (outbuf_len < FF_MIN_BUFFER_SIZE) outbuf_len = FF_MIN_BUFFER_SIZE; outbuf = (uint8_t *)av_malloc(outbuf_len); if (!outbuf) { DPRINTF(E_LOG, L_ART, "Out of memory for encoded artwork buffer\n"); #if LIBAVFORMAT_VERSION_MAJOR >= 53 avio_evbuffer_close(dst_ctx->pb); #else url_fclose(dst_ctx->pb); #endif ret = -1; goto out_free_buf; } #if LIBAVCODEC_VERSION_MAJOR >= 54 av_init_packet(&pkt); pkt.data = outbuf; pkt.size = outbuf_len; ret = avcodec_encode_video2(dst, &pkt, o_frame, &have_frame); if (!ret && have_frame && dst->coded_frame) { dst->coded_frame->pts = pkt.pts; dst->coded_frame->key_frame = !!(pkt.flags & AV_PKT_FLAG_KEY); } else if (ret < 0) { DPRINTF(E_LOG, L_ART, "Could not encode artwork\n"); ret = -1; goto out_fclose_dst; } #else ret = avcodec_encode_video(dst, outbuf, outbuf_len, o_frame); if (ret <= 0) { DPRINTF(E_LOG, L_ART, "Could not encode artwork\n"); ret = -1; goto out_fclose_dst; } av_init_packet(&pkt); pkt.stream_index = 0; pkt.data = outbuf; pkt.size = ret; #endif #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3) ret = avformat_write_header(dst_ctx, NULL); #else ret = av_write_header(dst_ctx); #endif if (ret != 0) { DPRINTF(E_LOG, L_ART, "Could not write artwork header: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_fclose_dst; } ret = av_interleaved_write_frame(dst_ctx, &pkt); if (ret != 0) { DPRINTF(E_LOG, L_ART, "Error writing artwork\n"); ret = -1; goto out_fclose_dst; } ret = av_write_trailer(dst_ctx); if (ret != 0) { DPRINTF(E_LOG, L_ART, "Could not write artwork trailer: %s\n", strerror(AVUNERROR(ret))); ret = -1; goto out_fclose_dst; } switch (dst_fmt->video_codec) { case CODEC_ID_PNG: ret = ART_FMT_PNG; break; case CODEC_ID_MJPEG: ret = ART_FMT_JPEG; break; default: DPRINTF(E_LOG, L_ART, "Unhandled rescale output format\n"); ret = -1; break; } out_fclose_dst: #if LIBAVFORMAT_VERSION_MAJOR >= 53 avio_evbuffer_close(dst_ctx->pb); #else url_fclose(dst_ctx->pb); #endif av_free(outbuf); out_free_buf: av_free(buf); out_free_frames: if (i_frame) av_free(i_frame); if (o_frame) av_free(o_frame); avcodec_close(dst); out_free_dst_ctx: avformat_free_context(dst_ctx); out_close_src: avcodec_close(src); return ret; }