// // Created by bxc on 2023/4/18. // 作者:北小菜 // 邮箱:bilibili_bxc@126.com // 西瓜视频主页:https://www.ixigua.com/home/4171970536803763 // 哔哩哔哩主页:https://space.bilibili.com/487906612/ // #include "FFRtpParser.h" #include "Utils.h" #include int avio_read_packet(void* opaque, uint8_t* buf, int buffsize){ FFRtpParser* player = (FFRtpParser*)opaque; int ret = 0; if (player->bufferSize >= buffsize) { memcpy(buf, player->buffer, buffsize); player->bufferSize = player->bufferSize - buffsize; memmove(player->buffer, player->buffer + buffsize, player->bufferSize); ret = buffsize; LOG_INFO("avio_read_packet=%d", buffsize); } return ret; } FFRtpParser::FFRtpParser() { } FFRtpParser::~FFRtpParser() { if (mVideoCodecPar) { avcodec_parameters_free(&mVideoCodecPar); } if (mVideoCodecCtx) { avcodec_close(mVideoCodecCtx); mVideoCodecCtx = nullptr; } if (mFmtCtx) { avformat_close_input(&mFmtCtx); mFmtCtx = nullptr; } } bool FFRtpParser::probe() { mFmtCtx = avformat_alloc_context(); unsigned char* avioBuff = (unsigned char*)av_malloc(1920 * 1080); mAvioCtx = avio_alloc_context(avioBuff, sizeof(avioBuff), 0, this, avio_read_packet, NULL, NULL); //探测流(获取码流格式) if (av_probe_input_buffer2(mAvioCtx, (const AVInputFormat**)&mInputFmt, "", NULL, 0, 0) < 0){ LOG_ERROR("av_probe_input_buffer2 error"); return false; } mFmtCtx->pb = mAvioCtx; //配置流参数 //av_dict_set(&options, "fflags", "nobuffer", 0); //不缓存直接解码 //打开流 if (avformat_open_input(&mFmtCtx, "", mInputFmt, &net_options) != 0) { LOG_ERROR("avformat_open_input error"); return false; } //获取流信息 if (avformat_find_stream_info(mFmtCtx, NULL) < 0)//? { LOG_ERROR("avformat_find_stream_info error"); return false; } //获取视频流 mVideoStream = av_find_best_stream(mFmtCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); if (mVideoStream < 0) { LOG_ERROR("av_find_best_stream error"); return false; } //获取解码信息 mVideoCodecPar = mFmtCtx->streams[mVideoStream]->codecpar; const AVCodec* videoCodec = avcodec_find_decoder(mVideoCodecPar->codec_id); if (!videoCodec){ LOG_ERROR("avcodec_find_decoder error"); return false; } mVideoCodecCtx = avcodec_alloc_context3(videoCodec); //codecpar为解码器上下文赋值 if (avcodec_parameters_to_context(mVideoCodecCtx, mVideoCodecPar) != 0) { LOG_ERROR("avcodec_parameters_to_context error"); return false; } //设置解码器参数 //av_dict_set(&codec_options, "tune", "zero-latency", 0);//设置零延迟 //av_dict_set(&codec_options, "preset", "ultrafast", 0);//设置最模糊但是最快的解码方式 //av_dict_set(&codec_options, "x265-params", "qp=20", 0);//设置265量化参数 //量化参数:控制了视频帧中每一个宏区块(Macroblock)的压缩量。较大的数值,量化值更高,意味着更多的压缩,更低的质量,较小的数值代表相反的含义。 //打开解码器 if (avcodec_open2(mVideoCodecCtx, videoCodec, &codec_options) < 0) { LOG_ERROR("avcodec_open2 error"); return false; } LOG_INFO("mVideoCodecCtx->width=%d,mVideoCodecCtx->height=%d", mVideoCodecCtx->width, mVideoCodecCtx->height); return true; } void FFRtpParser::play(){ LOG_INFO("start"); AVPacket pkt; while (av_read_frame(mFmtCtx, &pkt) >= 0) { if (pkt.stream_index == mVideoStream){ } av_packet_unref(&pkt); } LOG_INFO("end"); }