static AVCodecContext *wrapped_avcodec_get_context(uint32_t cAVIdx, AVStream *stream) { #if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32)) AVCodecContext *avCodecCtx = restore_avcodec_context(cAVIdx, stream->id); if (!avCodecCtx) { avCodecCtx = avcodec_alloc_context3(NULL); if (!avCodecCtx) { ffmpeg_err("context3 alloc for stream %d failed\n", (int)stream->id); return NULL; } if (avcodec_parameters_to_context(avCodecCtx, stream->codecpar) < 0) { ffmpeg_err("parameters to context for stream %d failed\n", (int)stream->id); avcodec_free_context(&avCodecCtx); return NULL; } #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100) av_codec_set_pkt_timebase(avCodecCtx, stream->time_base); #else avCodecCtx->pkt_timebase = stream->time_base; #endif store_avcodec_context(avCodecCtx, cAVIdx, stream->id); return avCodecCtx; } #else return stream->codec; #endif }
FileOut::FileOut(string filename, int width, int height, AVCodecID avCodecID_video) : filename(filename) { av_register_all(); // Initialize AVPacket pkt.reset(&_pkt); av_init_packet(pkt.get()); pkt.get()->data = nullptr; pkt.get()->size = 0; // Get Codec Context AVCodec* videoCodec = avcodec_find_encoder(avCodecID_video); assert(videoCodec != nullptr); ccv.reset(avcodec_alloc_context3(videoCodec)); assert(ccv); // TEST CODE /* put sample parameters */ //ccv.get()->bit_rate = 400000; /* resolution must be a multiple of two */ ccv.get()->width = width; ccv.get()->height = height; /* frames per second */ AVRational r { 1, 30 }; ccv.get()->time_base = r; /* emit one intra frame every ten frames * check frame pict_type before passing frame * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I * then gop_size is ignored and the output of encoder * will always be I frame irrespective to gop_size */ ccv.get()->gop_size = 0; ccv.get()->max_b_frames = 0; ccv.get()->pix_fmt = AV_PIX_FMT_YUV420P; //ccv.get()->pkt_timebase = r; ccv.get()->time_base = r; ccv.get()->ticks_per_frame = 2; //ccv.get()->timecode_frame_start = 1; av_codec_set_pkt_timebase(ccv.get(), r); if (avCodecID_video == AV_CODEC_ID_H264) av_opt_set(ccv.get()->priv_data, "preset", "slow", 0); assert(avcodec_open2(ccv.get(), videoCodec, NULL) == 0); f = fopen(filename.c_str(), "wb"); assert(f); }
bool FFMpegLoader::open(qint64 &position) { if (!AbstractFFMpegLoader::open(position)) { return false; } int res = 0; char err[AV_ERROR_MAX_STRING_SIZE] = { 0 }; auto codecParams = fmtContext->streams[streamId]->codecpar; codecContext = avcodec_alloc_context3(nullptr); if (!codecContext) { LOG(("Audio Error: Unable to avcodec_alloc_context3 for file '%1', data size '%2'").arg(_file.name()).arg(_data.size())); return false; } if ((res = avcodec_parameters_to_context(codecContext, codecParams)) < 0) { LOG(("Audio Error: Unable to avcodec_parameters_to_context for file '%1', data size '%2', error %3, %4").arg(_file.name()).arg(_data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return false; } av_codec_set_pkt_timebase(codecContext, fmtContext->streams[streamId]->time_base); av_opt_set_int(codecContext, "refcounted_frames", 1, 0); if ((res = avcodec_open2(codecContext, codec, 0)) < 0) { LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(_file.name()).arg(_data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return false; } auto layout = codecParams->channel_layout; if (!layout) { auto channelsCount = codecParams->channels; switch (channelsCount) { case 1: layout = AV_CH_LAYOUT_MONO; break; case 2: layout = AV_CH_LAYOUT_STEREO; break; default: LOG(("Audio Error: Unknown channel layout for %1 channels.").arg(channelsCount)); break; } } inputFormat = codecContext->sample_fmt; switch (layout) { case AV_CH_LAYOUT_MONO: switch (inputFormat) { case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: fmt = AL_FORMAT_MONO8; sampleSize = 1; break; case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S16P: fmt = AL_FORMAT_MONO16; sampleSize = sizeof(uint16); break; default: sampleSize = -1; // convert needed break; } break; case AV_CH_LAYOUT_STEREO: switch (inputFormat) { case AV_SAMPLE_FMT_U8: fmt = AL_FORMAT_STEREO8; sampleSize = 2; break; case AV_SAMPLE_FMT_S16: fmt = AL_FORMAT_STEREO16; sampleSize = 2 * sizeof(uint16); break; default: sampleSize = -1; // convert needed break; } break; default: sampleSize = -1; // convert needed break; } if (_samplesFrequency != 44100 && _samplesFrequency != 48000) { sampleSize = -1; // convert needed } if (sampleSize < 0) { swrContext = swr_alloc(); if (!swrContext) { LOG(("Audio Error: Unable to swr_alloc for file '%1', data size '%2'").arg(_file.name()).arg(_data.size())); return false; } int64_t src_ch_layout = layout, dst_ch_layout = AudioToChannelLayout; srcRate = _samplesFrequency; AVSampleFormat src_sample_fmt = inputFormat, dst_sample_fmt = AudioToFormat; dstRate = (_samplesFrequency != 44100 && _samplesFrequency != 48000) ? Media::Player::kDefaultFrequency : _samplesFrequency; av_opt_set_int(swrContext, "in_channel_layout", src_ch_layout, 0); av_opt_set_int(swrContext, "in_sample_rate", srcRate, 0); av_opt_set_sample_fmt(swrContext, "in_sample_fmt", src_sample_fmt, 0); av_opt_set_int(swrContext, "out_channel_layout", dst_ch_layout, 0); av_opt_set_int(swrContext, "out_sample_rate", dstRate, 0); av_opt_set_sample_fmt(swrContext, "out_sample_fmt", dst_sample_fmt, 0); if ((res = swr_init(swrContext)) < 0) { LOG(("Audio Error: Unable to swr_init for file '%1', data size '%2', error %3, %4").arg(_file.name()).arg(_data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return false; } sampleSize = AudioToChannels * sizeof(short); _samplesFrequency = dstRate; _samplesCount = av_rescale_rnd(_samplesCount, dstRate, srcRate, AV_ROUND_UP); position = av_rescale_rnd(position, dstRate, srcRate, AV_ROUND_DOWN); fmt = AL_FORMAT_STEREO16; maxResampleSamples = av_rescale_rnd(AVBlockSize / sampleSize, dstRate, srcRate, AV_ROUND_UP); if ((res = av_samples_alloc_array_and_samples(&dstSamplesData, 0, AudioToChannels, maxResampleSamples, AudioToFormat, 0)) < 0) { LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(_file.name()).arg(_data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res))); return false; } } if (position) { int64 ts = (position * fmtContext->streams[streamId]->time_base.den) / (_samplesFrequency * fmtContext->streams[streamId]->time_base.num); if (av_seek_frame(fmtContext, streamId, ts, AVSEEK_FLAG_ANY) < 0) { if (av_seek_frame(fmtContext, streamId, ts, 0) < 0) { } } } return true; }
static av_cold int init_subtitles(AVFilterContext *ctx) { int j, ret, sid; int k = 0; AVDictionary *codec_opts = NULL; AVFormatContext *fmt = NULL; AVCodecContext *dec_ctx = NULL; AVCodec *dec = NULL; const AVCodecDescriptor *dec_desc; AVStream *st; AVPacket pkt; AssContext *ass = ctx->priv; /* Init libass */ ret = init(ctx); if (ret < 0) return ret; ass->track = ass_new_track(ass->library); if (!ass->track) { av_log(ctx, AV_LOG_ERROR, "Could not create a libass track\n"); return AVERROR(EINVAL); } /* Open subtitles file */ ret = avformat_open_input(&fmt, ass->filename, NULL, NULL); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Unable to open %s\n", ass->filename); goto end; } ret = avformat_find_stream_info(fmt, NULL); if (ret < 0) goto end; /* Locate subtitles stream */ if (ass->stream_index < 0) ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0); else { ret = -1; if (ass->stream_index < fmt->nb_streams) { for (j = 0; j < fmt->nb_streams; j++) { if (fmt->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { if (ass->stream_index == k) { ret = j; break; } k++; } } } } if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Unable to locate subtitle stream in %s\n", ass->filename); goto end; } sid = ret; st = fmt->streams[sid]; /* Load attached fonts */ for (j = 0; j < fmt->nb_streams; j++) { AVStream *st = fmt->streams[j]; if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT && attachment_is_font(st)) { const AVDictionaryEntry *tag = NULL; tag = av_dict_get(st->metadata, "filename", NULL, AV_DICT_MATCH_CASE); if (tag) { av_log(ctx, AV_LOG_DEBUG, "Loading attached font: %s\n", tag->value); ass_add_font(ass->library, tag->value, st->codecpar->extradata, st->codecpar->extradata_size); } else { av_log(ctx, AV_LOG_WARNING, "Font attachment has no filename, ignored.\n"); } } } /* Initialize fonts */ ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1); /* Open decoder */ dec = avcodec_find_decoder(st->codecpar->codec_id); if (!dec) { av_log(ctx, AV_LOG_ERROR, "Failed to find subtitle codec %s\n", avcodec_get_name(st->codecpar->codec_id)); return AVERROR(EINVAL); } dec_desc = avcodec_descriptor_get(st->codecpar->codec_id); if (dec_desc && !(dec_desc->props & AV_CODEC_PROP_TEXT_SUB)) { av_log(ctx, AV_LOG_ERROR, "Only text based subtitles are currently supported\n"); return AVERROR_PATCHWELCOME; } if (ass->charenc) av_dict_set(&codec_opts, "sub_charenc", ass->charenc, 0); if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,26,100)) av_dict_set(&codec_opts, "sub_text_format", "ass", 0); dec_ctx = avcodec_alloc_context3(dec); if (!dec_ctx) return AVERROR(ENOMEM); ret = avcodec_parameters_to_context(dec_ctx, st->codecpar); if (ret < 0) goto end; /* * This is required by the decoding process in order to rescale the * timestamps: in the current API the decoded subtitles have their pts * expressed in AV_TIME_BASE, and thus the lavc internals need to know the * stream time base in order to achieve the rescaling. * * That API is old and needs to be reworked to match behaviour with A/V. */ av_codec_set_pkt_timebase(dec_ctx, st->time_base); ret = avcodec_open2(dec_ctx, NULL, &codec_opts); if (ret < 0) goto end; if (ass->force_style) { char **list = NULL; char *temp = NULL; char *ptr = av_strtok(ass->force_style, ",", &temp); int i = 0; while (ptr) { av_dynarray_add(&list, &i, ptr); if (!list) { ret = AVERROR(ENOMEM); goto end; } ptr = av_strtok(NULL, ",", &temp); } av_dynarray_add(&list, &i, NULL); if (!list) { ret = AVERROR(ENOMEM); goto end; } ass_set_style_overrides(ass->library, list); av_free(list); } /* Decode subtitles and push them into the renderer (libass) */ if (dec_ctx->subtitle_header) ass_process_codec_private(ass->track, dec_ctx->subtitle_header, dec_ctx->subtitle_header_size); av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; while (av_read_frame(fmt, &pkt) >= 0) { int i, got_subtitle; AVSubtitle sub = {0}; if (pkt.stream_index == sid) { ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt); if (ret < 0) { av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n", av_err2str(ret)); } else if (got_subtitle) { const int64_t start_time = av_rescale_q(sub.pts, AV_TIME_BASE_Q, av_make_q(1, 1000)); const int64_t duration = sub.end_display_time; for (i = 0; i < sub.num_rects; i++) { char *ass_line = sub.rects[i]->ass; if (!ass_line) break; if (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57,25,100)) ass_process_data(ass->track, ass_line, strlen(ass_line)); else ass_process_chunk(ass->track, ass_line, strlen(ass_line), start_time, duration); } } } av_packet_unref(&pkt); avsubtitle_free(&sub); } end: av_dict_free(&codec_opts); avcodec_close(dec_ctx); avcodec_free_context(&dec_ctx); avformat_close_input(&fmt); return ret; }
int fe_decode_open(char *filename) { int i = -1; AVDictionary *l_iFormatOpts = NULL; printf("fe_decode_open: Decode audio file %s\n", filename); m_pFormatCtx = avformat_alloc_context(); // Enable this to use old slow MP3 Xing TOC #ifndef CODEC_ID_MP3 if ( LIBAVFORMAT_VERSION_INT > 3540580 ) { printf("fe_decode_open: Set usetoc to have old way of XING TOC reading (libavformat version: '%d')\n", LIBAVFORMAT_VERSION_INT); av_dict_set(&l_iFormatOpts, "usetoc", "0", 0); } #endif // Open file and make m_pFormatCtx if (avformat_open_input(&m_pFormatCtx, filename, NULL, &l_iFormatOpts) != 0) { printf("fe_decode_open: cannot open with 'avformat_open_input': %s\n", filename); return -1; } #ifndef CODEC_ID_MP3 if ( LIBAVFORMAT_VERSION_INT > 3540580 && l_iFormatOpts != NULL ) { av_dict_free(&l_iFormatOpts); } #endif #if LIBAVCODEC_VERSION_INT < 3622144 m_pFormatCtx->max_analyze_duration = 999999999; #endif // Retrieve stream information if (avformat_find_stream_info(m_pFormatCtx, NULL) < 0) { printf("fe_decode_open: cannot open find info '%s'\n", filename); printf("As documentation says this is pretty normal. So this not show stopper!\n"); } av_dump_format(m_pFormatCtx, 0, filename, 0); // Find the first video stream m_iAudioStream = -1; printf("fe_decode_open: File got streams: %d\n", m_pFormatCtx->nb_streams); for (i = 0; i < m_pFormatCtx->nb_streams; i++) { // If we have FFMpeg version which is less than 3.2 then we use older implementation #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 0) if (m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { #else if (m_pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { #endif m_iAudioStream = i; break; } } if (m_iAudioStream == -1) { printf("fe_decode_open: cannot find an audio stream: cannot open %s", filename); return -1; } // Find the decoder for the audio stream // If we have FFMpeg version which is less than 3.2 then we use older implementation #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 0) if (!(m_pCodec = avcodec_find_decoder(m_pFormatCtx->streams[m_iAudioStream]->codec_id))) { #else if (!(m_pCodec = avcodec_find_decoder(m_pFormatCtx->streams[m_iAudioStream]->codecpar->codec_id))) { #endif printf("fe_decode_open: cannot find a decoder for %s\n", filename); return -1; } // If we have FFMpeg version which is less than 3.2 then we use older implementation #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 0) // Get a pointer to the codec context for the video stream m_pCodecCtx = m_pFormatCtx->streams[m_iAudioStream]->codec; #else // Get a pointer to the codec context for the video stream //m_pCodecCtx = avcodec_alloc_context3(m_pCodec); m_pCodecCtx = avcodec_alloc_context3(NULL); // Add stream parameters to context if(avcodec_parameters_to_context(m_pCodecCtx, m_pFormatCtx->streams[m_iAudioStream]->codecpar)) { printf("fe_decode_open: cannot add Codec parameters: %s\n", filename); return -1; } // This is not needed anymore above FFMpeg version 4.0 #if LIBAVCODEC_VERSION_INT < 3805796 // Se timebase correct av_codec_set_pkt_timebase(m_pCodecCtx, m_pFormatCtx->streams[m_iAudioStream]->time_base); #endif // Make sure that Codecs are identical or avcodec_open2 fails. m_pCodecCtx->codec_id = m_pCodec->id; #endif if(!m_pCodecCtx) { printf("fe_decode_open: cannot get 'AVCodecContext'\n"); return -1; } if (avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) { printf("fe_decode_open: cannot open with 'avcodec_open2' codec_id: %d Audio stream id: %d: %s\n", m_pFormatCtx->streams[m_iAudioStream]->codecpar->codec_id, m_iAudioStream, filename ); return -1; } printf("fe_decode_open: PCM Length is: %f (Bytes: %ld)\n", (double)(m_pFormatCtx->duration / AV_TIME_BASE), (int64_t)round((double)(m_pFormatCtx->duration / AV_TIME_BASE) * (44100 * 4))); m_lPcmLength = (int64_t)round((double)(m_pFormatCtx->duration / AV_TIME_BASE) * (44100 * 4)); return 0; }