ffmpeg解封裝,學習記錄。
阿新 • • 發佈:2018-12-22
CFilePlugEx::CFilePlugEx(INT uiSocketIndex, UINT uiPkgSize, string&sourcePath, BYTE _type) : m_sourcePath(sourcePath) ,m_uiPagSize(uiPkgSize) , m_uiSocketIndex(uiSocketIndex) , m_pIfmtCtx(nullptr) ,m_type(_type) { m_nVideoIndex = -1; m_nAudioIndex = -1; m_bIsInitSuccess = false; m_nBufSize = 0; m_nBufIndex = 0; m_bIsInitSuccess = InitFFmepg(); } CFilePlugEx::~CFilePlugEx() { } bool CFilePlugEx::StartSendAV(std::function<void(char*fileBuf, int len, UINT uiSocketIndex, BYTE _type)> lambdaCallBabck) { if (!m_bIsInitSuccess) { MessageBox(0, L"FFMEPG 初始化錯誤\n", L"錯誤", 0); return false; } if (m_nBufIndex >= m_nBufSize) { m_nBufIndex = 0; m_nBufSize = 0; if(!ReadFrame(m_avPkt, m_nBufSize)) { if (m_nBufSize == -1)//讀取檔案錯誤,可能讀完了流 { MessageBox(0, L"讀取檔案錯誤,可能讀完了流\n", L"錯誤", 0); return false; } if (m_nBufSize == 0)//可能讀取了異常資料幀 { av_free_packet(&m_avPkt); m_avPkt.size = 0; return true; } } } int len1 = m_nBufSize - m_nBufIndex; if (len1 >m_uiPagSize)//剩餘的資料 比預設的大 { lambdaCallBabck((char*)m_avPkt.data + m_nBufIndex, m_uiPagSize, m_uiSocketIndex, m_type); m_nBufIndex += m_uiPagSize; } if (len1<= m_uiPagSize) //剩餘的小於預設值 不完整簡單處理髮送。 { lambdaCallBabck((char*)m_avPkt.data + m_nBufIndex, len1, m_uiSocketIndex, m_type); m_nBufIndex = 0; m_nBufSize = 0; av_free_packet(&m_avPkt); m_avPkt.size = 0; } return true; } void CFilePlugEx::StopSendAv() { av_free_packet(&m_avPkt); avformat_close_input(&m_pIfmtCtx); } bool CFilePlugEx::InitFFmepg() { av_register_all(); if ((avformat_open_input(&m_pIfmtCtx, m_sourcePath.c_str(), 0, 0)) < 0) { TRACE("Could not open input file.\n"); goto end; } if ((avformat_find_stream_info(m_pIfmtCtx, 0)) < 0) { TRACE("Failed to retrieve input stream information\n"); goto end; } for (auto i = 0; i < m_pIfmtCtx->nb_streams; i++) { AVStream *in_stream = m_pIfmtCtx->streams[i]; if (in_stream->codec->codec_id == AV_CODEC_ID_NONE && m_pIfmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { in_stream->codec->codec_id = AV_CODEC_ID_PCM_ALAW; in_stream->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW; } if (m_pIfmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (m_nVideoIndex != -1) { continue; } m_nVideoIndex = i; } else if (m_pIfmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (m_nAudioIndex != -1) { continue; } m_nAudioIndex = i; } else { break; } } if (m_nAudioIndex == -1&& m_nVideoIndex == -1) { TRACE("Failed to find stream\n"); goto end; } avcodec_register_all(); return true; end: avformat_close_input(&m_pIfmtCtx); return false; } int my_av_bsf_filter(const AVBitStreamFilter *filter, AVPacket *pPacket, const AVCodecParameters *src) { int ret; AVBSFContext *ctx = NULL; if (!filter) return 0; ret = av_bsf_alloc(filter, &ctx); if (ret < 0) return ret; ret = avcodec_parameters_copy(ctx->par_in, src); if (ret < 0) return ret; ret = av_bsf_init(ctx); if (ret < 0) return ret; AVPacket pkt = { 0 }; pkt.data = pPacket->data; pkt.size = pPacket->size; ret = av_bsf_send_packet(ctx, &pkt); if (ret < 0) return ret; ret = av_bsf_receive_packet(ctx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return 0; else if (ret < 0) return ret; uint8_t **poutbuf = &(pPacket->data); int *poutbuf_size = &(pPacket->size); *poutbuf = (uint8_t*)av_malloc(pkt.size + AV_INPUT_BUFFER_PADDING_SIZE); if (!*poutbuf) { av_packet_unref(&pkt); return AVERROR(ENOMEM); } *poutbuf_size = pkt.size; memcpy(*poutbuf, pkt.data, pkt.size); av_packet_unref(&pkt); /* drain all the remaining packets we cannot return */ while (ret >= 0) { ret = av_bsf_receive_packet(ctx, &pkt); av_packet_unref(&pkt); } av_bsf_free(&ctx); return 1; } bool CFilePlugEx::ReadFrame(AVPacket &pkt, unsigned int &len) { const AVBitStreamFilter *pavBitStFilter = av_bsf_get_by_name("h264_mp4toannexb"); AVStream *in_stream; if (av_read_frame(m_pIfmtCtx, &pkt) < 0) { len = -1; return false; } in_stream = m_pIfmtCtx->streams[pkt.stream_index]; if (pkt.stream_index == m_nVideoIndex) {//視訊流 if (m_type == 0x10) { my_av_bsf_filter(pavBitStFilter, &pkt, in_stream->codecpar); len = pkt.size; } } else if(pkt.stream_index == m_nAudioIndex)//音訊流 { if (m_type == 0x01) { len = pkt.size; } } else//其他型別的,此時還未結束 可能讀取異常 { len = 0; return false; } return true; }