Initial commit
This commit is contained in:
commit
c4a6e2f0bf
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.idea/
|
||||||
|
|
||||||
16
CMakeLists.txt
Normal file
16
CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
project(ffConv)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -ggdb -Og")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -std=c++14 -ggdb -Og")
|
||||||
|
|
||||||
|
find_package(FFMPEG REQUIRED)
|
||||||
|
include_directories(${FFMPEG_INCLUDE_DIRS})
|
||||||
|
link_directories(${FFMPEG_LIBRARY_DIRS})
|
||||||
|
|
||||||
|
#message(FATAL_ERROR ${FFMPEG_LIBRARIES})
|
||||||
|
|
||||||
|
set(SOURCE_FILES main.cpp)
|
||||||
|
add_executable(ffConv ${SOURCE_FILES})
|
||||||
|
target_link_libraries(ffConv ${FFMPEG_LIBRARIES})
|
||||||
145
cmake/modules/FindFFMPEG.cmake
Normal file
145
cmake/modules/FindFFMPEG.cmake
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
# - Try to find FFMPEG
|
||||||
|
# Once done this will define
|
||||||
|
# FFMPEG_FOUND - System has FFMPEG
|
||||||
|
# FFMPEG_INCLUDE_DIRS - The FFMPEG include directories
|
||||||
|
# FFMPEG_LIBRARIES - The libraries needed to use FFMPEG
|
||||||
|
# FFMPEG_LIBRARY_DIRS - The directory to find FFMPEG libraries
|
||||||
|
#
|
||||||
|
# written by Roy Shilkrot 2013 http://www.morethantechnical.com/
|
||||||
|
#
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
|
||||||
|
MACRO(FFMPEG_FIND varname shortname headername)
|
||||||
|
|
||||||
|
IF(NOT WIN32)
|
||||||
|
PKG_CHECK_MODULES(PC_${varname} ${shortname})
|
||||||
|
|
||||||
|
FIND_PATH(${varname}_INCLUDE_DIR "${shortname}/${headername}"
|
||||||
|
HINTS ${PC_${varname}_INCLUDEDIR} ${PC_${varname}_INCLUDE_DIRS}
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
ELSE()
|
||||||
|
FIND_PATH(${varname}_INCLUDE_DIR "${shortname}/${headername}")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(${varname}_INCLUDE_DIR STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND")
|
||||||
|
message(STATUS "look for newer strcture")
|
||||||
|
IF(NOT WIN32)
|
||||||
|
PKG_CHECK_MODULES(PC_${varname} "lib${shortname}")
|
||||||
|
|
||||||
|
FIND_PATH(${varname}_INCLUDE_DIR "lib${shortname}/${headername}"
|
||||||
|
HINTS ${PC_${varname}_INCLUDEDIR} ${PC_${varname}_INCLUDE_DIRS}
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
ELSE()
|
||||||
|
FIND_PATH(${varname}_INCLUDE_DIR "lib${shortname}/${headername}")
|
||||||
|
IF(${${varname}_INCLUDE_DIR} STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND")
|
||||||
|
#Desperate times call for desperate measures
|
||||||
|
MESSAGE(STATUS "globbing...")
|
||||||
|
FILE(GLOB_RECURSE ${varname}_INCLUDE_DIR "/ffmpeg*/${headername}")
|
||||||
|
MESSAGE(STATUS "found: ${${varname}_INCLUDE_DIR}")
|
||||||
|
IF(${varname}_INCLUDE_DIR)
|
||||||
|
GET_FILENAME_COMPONENT(${varname}_INCLUDE_DIR "${${varname}_INCLUDE_DIR}" PATH)
|
||||||
|
GET_FILENAME_COMPONENT(${varname}_INCLUDE_DIR "${${varname}_INCLUDE_DIR}" PATH)
|
||||||
|
ELSE()
|
||||||
|
SET(${varname}_INCLUDE_DIR "${varname}_INCLUDE_DIR-NOTFOUND")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(${${varname}_INCLUDE_DIR} STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND")
|
||||||
|
MESSAGE(STATUS "Can't find includes for ${shortname}...")
|
||||||
|
ELSE()
|
||||||
|
MESSAGE(STATUS "Found ${shortname} include dirs: ${${varname}_INCLUDE_DIR}")
|
||||||
|
|
||||||
|
# GET_DIRECTORY_PROPERTY(FFMPEG_PARENT DIRECTORY ${${varname}_INCLUDE_DIR} PARENT_DIRECTORY)
|
||||||
|
GET_FILENAME_COMPONENT(FFMPEG_PARENT ${${varname}_INCLUDE_DIR} PATH)
|
||||||
|
MESSAGE(STATUS "Using FFMpeg dir parent as hint: ${FFMPEG_PARENT}")
|
||||||
|
|
||||||
|
IF(NOT WIN32)
|
||||||
|
FIND_LIBRARY(${varname}_LIBRARIES NAMES ${shortname}
|
||||||
|
HINTS ${PC_${varname}_LIBDIR} ${PC_${varname}_LIBRARY_DIR} ${FFMPEG_PARENT})
|
||||||
|
ELSE()
|
||||||
|
# FIND_PATH(${varname}_LIBRARIES "${shortname}.dll.a" HINTS ${FFMPEG_PARENT})
|
||||||
|
FILE(GLOB_RECURSE ${varname}_LIBRARIES "${FFMPEG_PARENT}/*${shortname}.lib")
|
||||||
|
# GLOBing is very bad... but windows sux, this is the only thing that works
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
IF(${varname}_LIBRARIES STREQUAL "${varname}_LIBRARIES-NOTFOUND")
|
||||||
|
MESSAGE(STATUS "look for newer structure for library")
|
||||||
|
FIND_LIBRARY(${varname}_LIBRARIES NAMES lib${shortname}
|
||||||
|
HINTS ${PC_${varname}_LIBDIR} ${PC_${varname}_LIBRARY_DIR} ${FFMPEG_PARENT})
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
|
||||||
|
IF(${varname}_LIBRARIES STREQUAL "${varname}_LIBRARIES-NOTFOUND")
|
||||||
|
MESSAGE(STATUS "Can't find lib for ${shortname}...")
|
||||||
|
ELSE()
|
||||||
|
MESSAGE(STATUS "Found ${shortname} libs: ${${varname}_LIBRARIES}")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
|
||||||
|
IF(NOT ${varname}_INCLUDE_DIR STREQUAL "${varname}_INCLUDE_DIR-NOTFOUND"
|
||||||
|
AND NOT ${varname}_LIBRARIES STREQUAL ${varname}_LIBRARIES-NOTFOUND)
|
||||||
|
|
||||||
|
MESSAGE(STATUS "found ${shortname}: include ${${varname}_INCLUDE_DIR} lib ${${varname}_LIBRARIES}")
|
||||||
|
SET(FFMPEG_${varname}_FOUND 1)
|
||||||
|
SET(FFMPEG_${varname}_INCLUDE_DIRS ${${varname}_INCLUDE_DIR})
|
||||||
|
SET(FFMPEG_${varname}_LIBS ${${varname}_LIBRARIES})
|
||||||
|
SET(FFMPEG_${varname}_LIBDIR ${PC_${varname}_LIBDIR})
|
||||||
|
|
||||||
|
ELSE()
|
||||||
|
MESSAGE(STATUS "Can't find ${shortname}")
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
ENDMACRO(FFMPEG_FIND)
|
||||||
|
|
||||||
|
FFMPEG_FIND(LIBAVFORMAT avformat avformat.h)
|
||||||
|
FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h)
|
||||||
|
FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h)
|
||||||
|
FFMPEG_FIND(LIBAVUTIL avutil avutil.h)
|
||||||
|
FFMPEG_FIND(LIBSWSCALE swscale swscale.h)
|
||||||
|
|
||||||
|
SET(FFMPEG_FOUND "NO")
|
||||||
|
IF (FFMPEG_LIBAVFORMAT_FOUND AND
|
||||||
|
FFMPEG_LIBAVDEVICE_FOUND AND
|
||||||
|
FFMPEG_LIBAVCODEC_FOUND AND
|
||||||
|
FFMPEG_LIBAVUTIL_FOUND AND
|
||||||
|
FFMPEG_LIBSWSCALE_FOUND
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SET(FFMPEG_FOUND "YES")
|
||||||
|
|
||||||
|
SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBDIR})
|
||||||
|
|
||||||
|
SET(FFMPEG_LIBRARIES
|
||||||
|
${FFMPEG_LIBAVFORMAT_LIBS}
|
||||||
|
${FFMPEG_LIBAVDEVICE_LIBS}
|
||||||
|
${FFMPEG_LIBAVCODEC_LIBS}
|
||||||
|
${FFMPEG_LIBAVUTIL_LIBS}
|
||||||
|
${FFMPEG_LIBSWSCALE_LIBS}
|
||||||
|
)
|
||||||
|
|
||||||
|
ELSE ()
|
||||||
|
|
||||||
|
MESSAGE(STATUS "Could not find FFMPEG")
|
||||||
|
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
message(STATUS ${FFMPEG_LIBRARIES} ${FFMPEG_LIBAVFORMAT_LIBRARIES})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set FFMPEG_FOUND to TRUE
|
||||||
|
# if all listed variables are TRUE
|
||||||
|
find_package_handle_standard_args(FFMPEG DEFAULT_MSG
|
||||||
|
FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS)
|
||||||
|
|
||||||
|
mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARY_DIRS FFMPEG_LIBRARIES)
|
||||||
148
main.cpp
Normal file
148
main.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkResult(int res, const char* msg) {
|
||||||
|
if(res < 0) {
|
||||||
|
char errStr[260];
|
||||||
|
av_strerror(res, errStr, 260);
|
||||||
|
std::cout << msg << ": " << errStr << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
AVFormatContext* inFmtCtx = nullptr;
|
||||||
|
AVFormatContext* outFmtCtx = nullptr;
|
||||||
|
|
||||||
|
av_register_all();
|
||||||
|
int res = avformat_open_input(&inFmtCtx, argv[1], nullptr, nullptr);
|
||||||
|
checkResult(res, "cannot open input");
|
||||||
|
|
||||||
|
res = avformat_find_stream_info(inFmtCtx, nullptr);
|
||||||
|
checkResult(res, "cannot find stream info");
|
||||||
|
|
||||||
|
res = avformat_alloc_output_context2(&outFmtCtx, nullptr, nullptr, argv[2]);
|
||||||
|
checkResult(res, "cannot allocate output context");
|
||||||
|
|
||||||
|
AVStream *videoStream = nullptr, *audioStream = nullptr;
|
||||||
|
for(int i = 0; i < inFmtCtx->nb_streams; ++i) {
|
||||||
|
AVStream* stream = inFmtCtx->streams[i];
|
||||||
|
if(stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
std::cout << "found video stream " << avcodec_get_name(stream->codec->codec_id) << std::endl;
|
||||||
|
videoStream = stream;
|
||||||
|
} else if(stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||||
|
std::cout << "found audio stream " << avcodec_get_name(stream->codec->codec_id) << std::endl;
|
||||||
|
audioStream = stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodecContext* codecCtx = videoStream->codec;
|
||||||
|
AVCodec* codec = avcodec_find_decoder(codecCtx->codec_id);
|
||||||
|
if(!codec) std::cout << "cannot find decoder" << std::endl;
|
||||||
|
|
||||||
|
res = avcodec_open2(codecCtx, codec, nullptr);
|
||||||
|
checkResult(res, "cannot open codec for decoding");
|
||||||
|
|
||||||
|
// coder
|
||||||
|
AVCodec* dstVCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
|
||||||
|
if(!dstVCodec) std::cout << "cannot find encoder" << std::endl;
|
||||||
|
|
||||||
|
AVCodecContext* dstVCodecCtx = avcodec_alloc_context3(dstVCodec);
|
||||||
|
if(!dstVCodecCtx) std::cout << "cannot allocate context" << std::endl;
|
||||||
|
|
||||||
|
dstVCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
|
||||||
|
dstVCodecCtx->width = codecCtx->width;
|
||||||
|
dstVCodecCtx->height = codecCtx->height;
|
||||||
|
dstVCodecCtx->time_base = codecCtx->time_base;
|
||||||
|
outFmtCtx->duration = inFmtCtx->duration;
|
||||||
|
|
||||||
|
res = avcodec_open2(dstVCodecCtx, dstVCodec, nullptr);
|
||||||
|
checkResult(res, "cannot open codec for encoding");
|
||||||
|
|
||||||
|
if(outFmtCtx->oformat->flags & AVFMT_GLOBALHEADER)
|
||||||
|
dstVCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||||
|
|
||||||
|
AVStream* outVideoStream = avformat_new_stream(outFmtCtx, dstVCodec);
|
||||||
|
if(!outVideoStream) std::cout << "cannot create output video stream" << std::endl;
|
||||||
|
|
||||||
|
if (!(outFmtCtx->oformat->flags & AVFMT_NOFILE)) {
|
||||||
|
res = avio_open(&outFmtCtx->pb, argv[2], AVIO_FLAG_WRITE);
|
||||||
|
checkResult(res, "cannot open output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
av_dump_format(outFmtCtx, 0, argv[2], 1);
|
||||||
|
|
||||||
|
res = avformat_write_header(outFmtCtx, nullptr);
|
||||||
|
checkResult(res, "error writing header to output file");
|
||||||
|
|
||||||
|
AVPacket packet;
|
||||||
|
packet.data = nullptr;
|
||||||
|
packet.size = 0;
|
||||||
|
AVFrame* frame = nullptr;
|
||||||
|
int gotPicture = 0, gotPacket = 0, decodedFrames = 1;
|
||||||
|
while(true) {
|
||||||
|
res = av_read_frame(inFmtCtx, &packet);
|
||||||
|
if(res < 0) break;
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
if(!frame) break;
|
||||||
|
|
||||||
|
AVMediaType packetType = inFmtCtx->streams[packet.stream_index]->codec->codec_type;
|
||||||
|
if(packetType == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
res = avcodec_decode_video2(codecCtx, frame, &gotPicture, &packet);
|
||||||
|
if(res < 0) {
|
||||||
|
av_frame_free(&frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gotPicture) {
|
||||||
|
frame->pts = av_frame_get_best_effort_timestamp(frame);
|
||||||
|
std::cout << "decoded frame: " << decodedFrames++ << std::endl;
|
||||||
|
|
||||||
|
AVPacket encPacket;
|
||||||
|
encPacket.data = nullptr;
|
||||||
|
encPacket.size = 0;
|
||||||
|
av_init_packet(&encPacket);
|
||||||
|
encPacket.stream_index = 0;
|
||||||
|
|
||||||
|
encPacket.pts = decodedFrames;
|
||||||
|
encPacket.dts = decodedFrames;
|
||||||
|
|
||||||
|
res = avcodec_encode_video2(dstVCodecCtx, &encPacket, frame, &gotPacket);
|
||||||
|
av_frame_free(&frame);
|
||||||
|
if(res < 0) break;
|
||||||
|
if(!gotPacket) continue;
|
||||||
|
|
||||||
|
AVStream *st = outFmtCtx->streams[encPacket.stream_index];
|
||||||
|
auto x = st->codec->has_b_frames;
|
||||||
|
auto y = st->codec->max_b_frames;
|
||||||
|
|
||||||
|
//av_packet_rescale_ts(&encPacket, st->codec->time_base, st->time_base);
|
||||||
|
|
||||||
|
res = av_interleaved_write_frame(outFmtCtx, &encPacket);
|
||||||
|
checkResult(res, "cannot write frame to output file");
|
||||||
|
if(res < 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
av_free_packet(&packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
av_write_trailer(outFmtCtx);
|
||||||
|
|
||||||
|
|
||||||
|
if(codecCtx)
|
||||||
|
avcodec_close(codecCtx);
|
||||||
|
|
||||||
|
if(dstVCodecCtx)
|
||||||
|
avcodec_close(dstVCodecCtx);
|
||||||
|
|
||||||
|
if(inFmtCtx)
|
||||||
|
avformat_close_input(&inFmtCtx);
|
||||||
|
|
||||||
|
avformat_free_context(outFmtCtx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user