Notice
Link
- Today
- Total
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- vc++
- 피쉬랜드
- 파티션 빠른 삭제
- MySQL
- MFC
- 코드로 서버 재실행
- CSS
- 가변영역 스크롤
- 말줌임 CSS
- Back 키 클릭 감지
- rn
- mybatis exception
- pid 찾아 kill
- SQL 마지막날
- kill -9
- ffmpeg
- CentOS
- view 획득
- DB 계정생성
- Activity 전체화면
- reactnative
- springboot 재가동
- 스크롤적용
- MariaDB
- c언어
- springboot
- 텍스트컬러
- 터치좌표 view
- sql exception
- SQL 첫날
Archives
개발은 하는건가..
[FFMPEG] H264 AvPacket 데이터를 mp4 파일로 만들기 본문
반응형
AvPacket 를 raw 형태 그대로 저장한 파일을 mp4 파일 형태로 만든 코드이다.
m_RecordFile 이 raw 파일을 open 한 CFile 형태이므로 m_RecordFile 사용하는 부분만 필요한 형태로 교체하면된다.
CVideoRecorder::SRecordFrameInfo 이 구조체도 raw 파일 저장 시 영상크기나 코덱 정보를 저장했던 구조체이므로 반드시 필요하진 않으므로 영상크기만 필요한 형태로 교체해주면 된다.
BOOL CRecordFilePlayer::ExportRecordFile(CString &strFileName)
{
BOOL bResult = FALSE;
AVFormatContext* m_pOfmt_ctx = NULL;
AVCodecParameters codecpar;
AVStream* pOutVideoStream = NULL;
UINT nOldPosition = 0;
UINT nFileTotalSize = 0, nReadSize = 0, nReqSize = 0;
UINT nAccPts = 1;
AVPacket avPacket;
BYTE* pPacketData = new BYTE[MAX_FRAME_BUFF_SIZE];
CVideoRecorder::SRecordFrameInfo rfi;
ZeroMemory(&codecpar, sizeof(AVCodecParameters));
if (avformat_alloc_output_context2(&m_pOfmt_ctx, NULL, NULL, CT2A(strFileName)) == 0) {
pOutVideoStream = avformat_new_stream(m_pOfmt_ctx, NULL);
if (pOutVideoStream != NULL) {
pOutVideoStream->time_base = { 1, 90000 };
codecpar.codec_id = AV_CODEC_ID_H264;
codecpar.codec_type = AVMEDIA_TYPE_VIDEO;
codecpar.width = m_RecordFileHdr.SVideoInfo.nWidth;
codecpar.height = m_RecordFileHdr.SVideoInfo.nHeight;
avcodec_parameters_copy(pOutVideoStream->codecpar, &codecpar);
pOutVideoStream->codecpar->codec_tag = 0;
if (!(m_pOfmt_ctx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&m_pOfmt_ctx->pb, CT2A(strFileName), AVIO_FLAG_WRITE) == 0) {
if (avformat_write_header(m_pOfmt_ctx, 0) < 0) {
TRACE("Record file header write failed.");
goto FINALIZE;
}
}
else {
TRACE("Record file av open failed.");
goto FINALIZE;
}
}
}
else {
goto FINALIZE;
}
// 기존 파일 포지션 저장 후 맨 처음 위치로 이동.
nFileTotalSize = (UINT)m_RecordFile.GetLength();
nOldPosition = (UINT)m_RecordFile.GetPosition();
m_RecordFile.Seek(sizeof(CVideoRecorder::SRecordHeader), CFile::begin);
av_init_packet(&avPacket);
avPacket.stream_index = 0;
avPacket.pos = -1;
while (m_RecordFile.GetPosition() < nFileTotalSize) {
nReqSize = sizeof(CVideoRecorder::SRecordFrameInfo);
nReadSize = m_RecordFile.Read(&rfi, nReqSize);
if (nReadSize != nReqSize) {
break;
}
nReqSize = rfi.nFrameSize;
nReadSize = m_RecordFile.Read(pPacketData, nReqSize);
if (nReqSize != nReadSize) {
break;
}
avPacket.pts = nAccPts;
avPacket.dts = nAccPts;
avPacket.flags = (rfi.nIsKeyFrame == TRUE) ? AV_PKT_FLAG_KEY : 0;
avPacket.data = pPacketData;
avPacket.size = nReqSize;
av_interleaved_write_frame(m_pOfmt_ctx, &avPacket);
nAccPts += (rfi.nFrameDuration * m_RecordFileHdr.SVideoInfo.nTimebase);
}
bResult = TRUE;
}
FINALIZE:
if (m_pOfmt_ctx != NULL) {
av_write_trailer(m_pOfmt_ctx);
if (!(m_pOfmt_ctx->oformat->flags & AVFMT_NOFILE)) {
avio_closep(&m_pOfmt_ctx->pb);
}
avformat_free_context(m_pOfmt_ctx);
}
if (pPacketData != NULL) {
delete[] pPacketData;
}
if (nOldPosition != 0) {
// 이전 파일 포지션 원복
m_RecordFile.Seek(nOldPosition, CFile::begin);
}
return bResult;
}
* 경우에 따라 AVCodecParameters 값이 원본 AvStream 의 codecpar 를 이용해야 하는 경우도 있다.
그때는 아래와 같이 처리하면 된다.
// 원본 스트림의 AvStream 구조체가 m_sAvStream 일 경우 아래와 같이 codec 파라메터를 출력 AvStream 에 codecpar 에 복제해준다.
pOutVideoStream->time_base = { 1, m_sAvStream.time_base.den };
avcodec_parameters_copy(pOutVideoStream->codecpar, m_sAvStream.codecpar);
'C, C++, MFC' 카테고리의 다른 글
CListCtrl 선택된 Item 인덱스 (0) | 2022.07.19 |
---|---|
[MFC] DC 에 동영상 출력 시 가장 빠르게 출력 하기 위한 방법 (0) | 2022.04.08 |
c 매크로 - 엔디안 변환 (0) | 2022.02.10 |
VC++ 타이틀바가 없는 프로그램에 아이콘 나오는 법 (0) | 2018.10.31 |
VC++ 소스로 이동되는 TRACE 출력 (0) | 2018.10.31 |
Comments