commit c4a6e2f0bfd9f34da6b8406df115c89f09e4f524 Author: Selim Mustafaev Date: Sun Jul 24 18:12:56 2016 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13bbe5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ba021ed --- /dev/null +++ b/CMakeLists.txt @@ -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}) \ No newline at end of file diff --git a/cmake/modules/FindFFMPEG.cmake b/cmake/modules/FindFFMPEG.cmake new file mode 100644 index 0000000..5a56709 --- /dev/null +++ b/cmake/modules/FindFFMPEG.cmake @@ -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) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..8bc1195 --- /dev/null +++ b/main.cpp @@ -0,0 +1,148 @@ +#include + +extern "C" { + #include +} + +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; +}