├── .gitattributes ├── CMakeLists.txt ├── FFCodec.cpp ├── FFCodec.h ├── FFDemuxer.cpp ├── FFDemuxer.h ├── FFFrameQueue.cpp ├── FFFrameQueue.h ├── FFFrameReceiver.h ├── FFHardware.cpp ├── FFHardware.h ├── FFInfo.h ├── FFInputStream.cpp ├── FFInputStream.h ├── FFPointer.h ├── LICENSE ├── README.md ├── VideoCommon.cpp ├── VideoCommon.h ├── VideoDecoder.cpp ├── VideoDecoder.h ├── VideoPlayer.cpp ├── VideoPlayer.h ├── VideoStream.h ├── lua_video_auto.cpp └── lua_video_auto.hpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LIB_NAME cc_video) 2 | 3 | set(INCLUDES 4 | ${CMAKE_CURRENT_SOURCE_DIR} 5 | ${COCOS2DX_ROOT_PATH}/cocos 6 | ${COCOS2DX_ROOT_PATH}/cocos/base 7 | ${COCOS2DX_ROOT_PATH}/cocos/platform 8 | ${COCOS2DX_ROOT_PATH}/extensions 9 | ${COCOS2DX_ROOT_PATH}/external 10 | ${COCOS2DX_ROOT_PATH}/external/glfw3/include/win32 11 | ${COCOS2DX_ROOT_PATH}/external/glfw/include/GLFW 12 | ${COCOS2DX_ROOT_PATH}/external/win32-specific/gles/include/OGLES 13 | ) 14 | if(BUILD_LUA_LIBS) 15 | list(APPEND INCLUDES 16 | ${COCOS2DX_ROOT_PATH}/external/lua/luajit/include 17 | ${COCOS2DX_ROOT_PATH}/external/lua/tolua) 18 | endif() 19 | foreach(dir ${INCLUDES}) 20 | if(EXISTS ${dir}) 21 | include_directories(${dir}) 22 | endif() 23 | endforeach() 24 | 25 | set(HEADER 26 | FFCodec.h 27 | FFDemuxer.h 28 | FFFrameQueue.h 29 | FFFrameReceiver.h 30 | FFHardware.h 31 | FFInfo.h 32 | FFInputStream.h 33 | FFPointer.h 34 | VideoCommon.h 35 | VideoDecoder.h 36 | VideoPlayer.h 37 | VideoStream.h 38 | ) 39 | 40 | set(SOURCE 41 | FFCodec.cpp 42 | FFDemuxer.cpp 43 | FFFrameQueue.cpp 44 | FFHardware.cpp 45 | FFInputStream.cpp 46 | VideoCommon.cpp 47 | VideoDecoder.cpp 48 | VideoPlayer.cpp 49 | ) 50 | 51 | if(BUILD_LUA_LIBS) 52 | list(APPEND HEADER 53 | lua_video_auto.hpp 54 | ) 55 | list(APPEND SOURCE 56 | lua_video_auto.cpp 57 | ) 58 | endif() 59 | 60 | add_library(${LIB_NAME} STATIC ${SOURCE} ${HEADER}) 61 | add_dependencies(${LIB_NAME} cocos2d) 62 | use_cocos2dx_compile_define(${LIB_NAME}) 63 | use_cocos2dx_compile_options(${LIB_NAME}) 64 | 65 | if(CC_VIDEO_DEPEND_LIBS) 66 | target_link_libraries(${LIB_NAME} ${CC_VIDEO_DEPEND_LIBS}) 67 | endif() 68 | 69 | if(BUILD_LUA_LIBS) 70 | target_compile_definitions(${LIB_NAME} PUBLIC _USRLUASTATIC) 71 | endif() 72 | 73 | if(FFMPEG_LIBRARY) 74 | #target_link_libraries(${LIB_NAME} ${FFMPEG_LIBRARY}) 75 | #set_target_properties(${LIB_NAME} PROPERTIES XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${FFMPEG_FRAMEWORK_PATH}) 76 | target_include_directories(${LIB_NAME} PUBLIC FFMPEG_INCLUDE_DIR) 77 | endif() 78 | 79 | set_target_properties(${LIB_NAME} 80 | PROPERTIES 81 | ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" 82 | LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" 83 | INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} 84 | ) 85 | 86 | if(XCODE OR VS) 87 | cocos_mark_code_files(${LIB_NAME}) 88 | endif() 89 | -------------------------------------------------------------------------------- /FFCodec.cpp: -------------------------------------------------------------------------------- 1 | #include "FFCodec.h" 2 | #include "FFHardware.h" 3 | #include 4 | 5 | using namespace std; 6 | using namespace ffmpeg; 7 | 8 | std::vector Codec::allCodecs; 9 | 10 | std::vector Codec::getAllCodecs() 11 | { 12 | if (allCodecs.empty()) 13 | { 14 | void* opaque = nullptr; 15 | auto codec = av_codec_iterate(&opaque); 16 | while (codec) 17 | { 18 | allCodecs.push_back(codec); 19 | codec = av_codec_iterate(&opaque); 20 | } 21 | } 22 | return allCodecs; 23 | } 24 | 25 | std::vector Codec::getAllEncoders() 26 | { 27 | std::vector ret; 28 | for (auto& c : getAllCodecs()) 29 | { 30 | if (av_codec_is_encoder(c) != 0) 31 | ret.push_back(c); 32 | } 33 | return ret; 34 | } 35 | 36 | std::vector Codec::getAllDecoders() 37 | { 38 | std::vector ret; 39 | for (auto& c : getAllCodecs()) 40 | { 41 | if (av_codec_is_decoder(c) != 0) 42 | ret.push_back(c); 43 | } 44 | return ret; 45 | } 46 | 47 | std::vector Codec::getEncoders(AVMediaType type, AVCodecID id, bool onlyHardware) 48 | { 49 | std::vector ret; 50 | for (auto& c : getAllEncoders()) 51 | { 52 | bool ok = c->type == type; 53 | ok &= !onlyHardware || avcodec_get_hw_config(c, 0); 54 | ok &= id == AV_CODEC_ID_NONE || c->id == id; 55 | if (ok) 56 | ret.push_back(c); 57 | } 58 | return ret; 59 | } 60 | 61 | std::vector Codec::getDecoders(AVMediaType type, AVCodecID id, bool onlyHardware) 62 | { 63 | std::vector ret; 64 | for (auto& c : getAllDecoders()) 65 | { 66 | bool ok = c->type == type; 67 | ok &= !onlyHardware || avcodec_get_hw_config(c, 0); 68 | ok &= id == AV_CODEC_ID_NONE || c->id == id; 69 | if (ok) 70 | ret.push_back(c); 71 | } 72 | return ret; 73 | } 74 | 75 | Codec::Codec() 76 | { 77 | } 78 | 79 | Codec::~Codec() 80 | { 81 | clean(); 82 | } 83 | 84 | bool Codec::init(AVCodec* codec_) 85 | { 86 | if (!codec_) 87 | return false; 88 | codecContext = avcodec_alloc_context3(codec_); 89 | if (!codecContext) 90 | { 91 | VERRO("can't allocate video codec context for codec %s", codec_->name); 92 | return false; 93 | } 94 | codec = codec_; 95 | // copy the type 96 | //codecContext->codec_type = codec->type; 97 | return true; 98 | } 99 | 100 | Codec* Codec::create(AVCodec* codec) 101 | { 102 | auto ret = new (nothrow) Codec(); 103 | if (ret&&ret->init(codec)) 104 | { 105 | ret->autorelease(); 106 | return ret; 107 | } 108 | delete ret; 109 | return nullptr; 110 | } 111 | 112 | Codec* Codec::createByName(const char* name, bool isEncoder) 113 | { 114 | return create( 115 | isEncoder ? 116 | avcodec_find_encoder_by_name(name) : 117 | avcodec_find_decoder_by_name(name)); 118 | } 119 | 120 | Codec* Codec::createById(AVCodecID id, bool isEncoder) 121 | { 122 | return create( 123 | isEncoder ? 124 | avcodec_find_encoder(id) : 125 | avcodec_find_decoder(id)); 126 | } 127 | 128 | bool Codec::open() 129 | { 130 | if (opened) 131 | return true; 132 | const auto ret = avcodec_open2(codecContext, codec, nullptr); 133 | if (ret < 0) 134 | { 135 | VERRO("can't open codec: %d", ret); 136 | return false; 137 | } 138 | opened = true; 139 | return true; 140 | } 141 | 142 | void Codec::setOption(const char* name, const char* value) 143 | { 144 | av_opt_set(codecContext->priv_data, name, value, 0); 145 | } 146 | 147 | void Codec::setOption(const char* name, int value) 148 | { 149 | av_opt_set_int(codecContext->priv_data, name, value, 0); 150 | } 151 | 152 | void Codec::setOption(const char* name, double value) 153 | { 154 | av_opt_set_double(codecContext->priv_data, name, value, 0); 155 | } 156 | 157 | void Codec::setGenericOption(const char* name, const char* value) 158 | { 159 | av_opt_set(codecContext, name, value, 0); 160 | } 161 | 162 | void Codec::setGlobalContainerHeader() 163 | { 164 | if(!opened) 165 | codecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; 166 | } 167 | 168 | void Codec::flushBuffers() 169 | { 170 | if(codecContext->codec) 171 | { 172 | avcodec_flush_buffers(codecContext); 173 | } 174 | } 175 | 176 | void Codec::clean() 177 | { 178 | if (codecContext) 179 | { 180 | avcodec_free_context(&codecContext); 181 | } 182 | } 183 | 184 | bool AudioDecoder::init(AVCodec* codec_) 185 | { 186 | return Codec::init(codec_) && codec_->type == AVMEDIA_TYPE_AUDIO; 187 | } 188 | 189 | AudioDecoder* AudioDecoder::createByName(const char* name) 190 | { 191 | auto ret = new (nothrow) AudioDecoder(); 192 | if (ret&&ret->init(avcodec_find_decoder_by_name(name))) 193 | { 194 | ret->autorelease(); 195 | return ret; 196 | } 197 | delete ret; 198 | return nullptr; 199 | } 200 | 201 | AudioDecoder* AudioDecoder::createById(AVCodecID id) 202 | { 203 | auto ret = new (nothrow) AudioDecoder(); 204 | if (ret&&ret->init(avcodec_find_decoder(id))) 205 | { 206 | ret->autorelease(); 207 | return ret; 208 | } 209 | delete ret; 210 | return nullptr; 211 | } 212 | 213 | bool VideoDecoder::init(AVCodec* codec_) 214 | { 215 | return Codec::init(codec_) && codec_->type == AVMEDIA_TYPE_VIDEO; 216 | } 217 | 218 | VideoDecoder* VideoDecoder::createByName(const char* name) 219 | { 220 | auto ret = new (nothrow) VideoDecoder(); 221 | if (ret&&ret->init(avcodec_find_decoder_by_name(name))) 222 | { 223 | ret->autorelease(); 224 | return ret; 225 | } 226 | delete ret; 227 | return nullptr; 228 | } 229 | 230 | VideoDecoder* VideoDecoder::createById(AVCodecID id) 231 | { 232 | auto ret = new (nothrow) VideoDecoder(); 233 | if (ret&&ret->init(avcodec_find_decoder(id))) 234 | { 235 | ret->autorelease(); 236 | return ret; 237 | } 238 | delete ret; 239 | return nullptr; 240 | } 241 | 242 | VideoDecoder::~VideoDecoder() 243 | { 244 | if (hwDeviceCtx) 245 | { 246 | av_buffer_unref(&hwDeviceCtx); 247 | } 248 | } 249 | 250 | bool VideoDecoder::open() 251 | { 252 | if (Hardware::isSupported(codec)) 253 | return openHardware() || Decoder::open(); 254 | return Decoder::open(); 255 | } 256 | 257 | bool VideoDecoder::openHardware(AVPixelFormat desiredSWFormat) 258 | { 259 | if (opened) 260 | return true; 261 | const auto configs = Hardware::getConfigs(codec); 262 | if(configs.empty()) 263 | return false; 264 | #if 0 265 | static std::unordered_set CodecNames; 266 | if (!CodecNames.count(codec->name)) 267 | { 268 | std::string hw_str; 269 | for (auto&& cfg : configs) 270 | { 271 | hw_str += "\n fmt="; 272 | const auto pname = av_pix_fmt_desc_get(cfg->pix_fmt)->name; 273 | hw_str += pname ? pname : "null"; 274 | hw_str += ", device="; 275 | const auto dname = av_hwdevice_get_type_name(cfg->device_type); 276 | hw_str += dname ? dname : "null"; 277 | } 278 | VINFO("possible hw_cfg for decoder %s:%s", codec->name, hw_str.c_str()); 279 | CodecNames.insert(codec->name); 280 | } 281 | #endif 282 | for (auto&& cfg : configs) 283 | { 284 | // devideCtx should be released by av_buffer_unref 285 | auto devideCtx = Hardware::createDeviceContext(codecContext, cfg); 286 | if(!devideCtx) 287 | continue; 288 | const auto sw = Hardware::getSoftwareFormats(devideCtx); 289 | std::vector possibleSW; 290 | for (auto&& f : sw) 291 | { 292 | if (sws_isSupportedInput(f)) 293 | possibleSW.push_back(f); 294 | } 295 | swFormat = AV_PIX_FMT_NONE; 296 | for (auto&& f : possibleSW) 297 | { 298 | if (f == desiredSWFormat) 299 | { 300 | swFormat = f; 301 | break; 302 | } 303 | } 304 | if (swFormat == AV_PIX_FMT_NONE && !possibleSW.empty()) 305 | { 306 | swFormat = possibleSW[0]; 307 | } 308 | if(swFormat == AV_PIX_FMT_NONE) 309 | { 310 | av_buffer_unref(&devideCtx); 311 | codecContext->hw_device_ctx = nullptr; 312 | continue; 313 | } 314 | hwFormat = Hardware::getHardwareFormat(cfg); 315 | hwDeviceType = cfg->device_type; 316 | hwDeviceCtx = devideCtx; 317 | #if 0 318 | std::string sw_str; 319 | for (auto&& f : possibleSW) 320 | { 321 | const auto pname = av_pix_fmt_desc_get(f)->name; 322 | sw_str += " "; 323 | sw_str += pname ? pname : "null"; 324 | } 325 | const auto pname = av_pix_fmt_desc_get(cfg->pix_fmt)->name; 326 | VINFO("possible sw_fmt for hw_fmt %s:%s", pname ? pname : "null", sw_str.c_str()); 327 | #endif 328 | break; 329 | } 330 | if(!hwDeviceCtx) 331 | return false; 332 | const auto ret = avcodec_open2(codecContext, codec, nullptr); 333 | if (ret < 0) 334 | { 335 | VERRO("can't open codec context: %d", ret); 336 | return false; 337 | } 338 | const auto dname = av_hwdevice_get_type_name(hwDeviceType); 339 | VINFO("hw_fmt=%s, sw_fmt=%s, device=%s", 340 | av_pix_fmt_desc_get(hwFormat)->name, 341 | av_pix_fmt_desc_get(swFormat)->name, 342 | dname ? dname : "null"); 343 | opened = true; 344 | return true; 345 | } 346 | 347 | AVPixelFormat VideoDecoder::getHardwareFormat() const 348 | { 349 | return hwFormat; 350 | } 351 | 352 | AVPixelFormat VideoDecoder::getSoftwareFormat() const 353 | { 354 | return swFormat; 355 | } 356 | -------------------------------------------------------------------------------- /FFCodec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base/CCRef.h" 3 | #include "VideoCommon.h" 4 | #include 5 | 6 | namespace ffmpeg 7 | { 8 | class Codec : public cocos2d::Ref 9 | { 10 | static std::vector allCodecs; 11 | public: 12 | static std::vector getAllCodecs(); 13 | static std::vector getAllEncoders(); 14 | static std::vector getAllDecoders(); 15 | static std::vector getEncoders( 16 | AVMediaType type, AVCodecID id = AV_CODEC_ID_NONE, bool onlyHardware = false); 17 | static std::vector getDecoders( 18 | AVMediaType type, AVCodecID id = AV_CODEC_ID_NONE, bool onlyHardware = false); 19 | protected: 20 | Codec(); 21 | virtual ~Codec(); 22 | virtual bool init(AVCodec* codec_); 23 | public: 24 | 25 | static Codec* create(AVCodec* codec); 26 | static Codec* createByName(const char* name, bool isEncoder = false); 27 | static Codec* createById(AVCodecID id, bool isEncoder = false); 28 | 29 | AVCodec* getCodec() const { return codec; } 30 | AVCodecContext* getCodecContext() const { return codecContext; } 31 | 32 | virtual bool open(); 33 | bool isOpen() const { return opened; } 34 | void setOption(const char* name, const char* value); 35 | void setOption(const char* name, int value); 36 | void setOption(const char* name, double value); 37 | void setGenericOption(const char* name, const char* value); 38 | // used by the Muxer for configuration purposes 39 | void setGlobalContainerHeader(); 40 | 41 | void flushBuffers(); 42 | 43 | protected: 44 | void clean(); 45 | bool opened = false; 46 | AVCodecContext* codecContext = nullptr; 47 | AVCodec* codec = nullptr; 48 | }; 49 | 50 | class Decoder : public Codec {}; 51 | 52 | class AudioDecoder : public Decoder 53 | { 54 | protected: 55 | bool init(AVCodec* codec_) override; 56 | public: 57 | static AudioDecoder* createByName(const char* name); 58 | static AudioDecoder* createById(AVCodecID id); 59 | }; 60 | 61 | class VideoDecoder : public Decoder 62 | { 63 | protected: 64 | bool init(AVCodec* codec_) override; 65 | public: 66 | static VideoDecoder* createByName(const char* name); 67 | static VideoDecoder* createById(AVCodecID id); 68 | ~VideoDecoder() override; 69 | bool open() override; 70 | bool openHardware(AVPixelFormat desiredSWFormat = AV_PIX_FMT_NONE); 71 | AVPixelFormat getHardwareFormat() const; 72 | AVPixelFormat getSoftwareFormat() const; 73 | bool isHardware() const { return hwDeviceCtx != nullptr; } 74 | protected: 75 | AVBufferRef* hwDeviceCtx = nullptr; 76 | AVHWDeviceType hwDeviceType = AV_HWDEVICE_TYPE_NONE; 77 | AVPixelFormat hwFormat = AV_PIX_FMT_NONE; 78 | AVPixelFormat swFormat = AV_PIX_FMT_NONE; 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /FFDemuxer.cpp: -------------------------------------------------------------------------------- 1 | #include "FFDemuxer.h" 2 | #include "FFPointer.h" 3 | 4 | using namespace std; 5 | using namespace ffmpeg; 6 | 7 | std::vector Demuxer::getInputFormats() 8 | { 9 | std::vector ret; 10 | void* opaque = nullptr; 11 | auto inputFormat = av_demuxer_iterate(&opaque); 12 | while (inputFormat) 13 | { 14 | ret.push_back(inputFormat); 15 | inputFormat = av_demuxer_iterate(&opaque); 16 | } 17 | return ret; 18 | } 19 | 20 | Demuxer::Demuxer() 21 | { 22 | } 23 | 24 | Demuxer::~Demuxer() 25 | { 26 | clean(); 27 | } 28 | 29 | bool Demuxer::init(const std::string& url, AVFormatContext* containerContext) 30 | { 31 | if (!containerContext) 32 | return false; 33 | this->url = url; 34 | this->containerContext = containerContext; 35 | 36 | int ret; 37 | if ((ret = avformat_open_input(&containerContext, url.c_str(), nullptr, nullptr)) < 0) 38 | { 39 | VERRO("Failed to open %s: %d", url.c_str(), ret); 40 | return false; 41 | } 42 | if ((ret = avformat_find_stream_info(containerContext, nullptr)) < 0) 43 | { 44 | VERRO("Failed to read streams from %s: %d", url.c_str(), ret); 45 | return false; 46 | } 47 | 48 | return true; 49 | } 50 | 51 | Demuxer* Demuxer::create(const std::string& url, AVFormatContext* containerContext) 52 | { 53 | auto ret = new (std::nothrow) Demuxer(); 54 | if (ret && ret->init(url, containerContext)) 55 | { 56 | ret->autorelease(); 57 | return ret; 58 | } 59 | delete ret; 60 | return nullptr; 61 | } 62 | 63 | bool Demuxer::setAudioReceiver(FrameReceiver* receiver, int streamIndex) 64 | { 65 | if (!receiver || receiver->getMediaType() != AVMEDIA_TYPE_AUDIO) 66 | { 67 | VERRO("invalid receiver"); 68 | return false; 69 | } 70 | return setReceiver(receiver, AVMEDIA_TYPE_AUDIO, streamIndex); 71 | } 72 | 73 | bool Demuxer::setVideoReceiver(FrameReceiver* receiver, int streamIndex) 74 | { 75 | if (!receiver || receiver->getMediaType() != AVMEDIA_TYPE_VIDEO) 76 | { 77 | VERRO("invalid receiver"); 78 | return false; 79 | } 80 | return setReceiver(receiver, AVMEDIA_TYPE_VIDEO, streamIndex); 81 | } 82 | 83 | void Demuxer::prepare() 84 | { 85 | bool allPrepared; 86 | do 87 | { 88 | step(); 89 | // see if all input streams are prepared 90 | allPrepared = true; 91 | for (auto& it : inputStreams) 92 | { 93 | if (!it.second->prepare()) 94 | allPrepared = false; 95 | } 96 | } while (!allPrepared && !isDone()); 97 | } 98 | 99 | bool Demuxer::isDone() 100 | { 101 | return done; 102 | } 103 | 104 | bool Demuxer::step() 105 | { 106 | auto pkt_ = newPacketPtr(); 107 | auto pkt = pkt_.get(); 108 | av_init_packet(pkt); 109 | pkt->data = nullptr; 110 | // read frames from the file 111 | int ret = av_read_frame(containerContext, pkt); 112 | // EOF 113 | if (ret == AVERROR_EOF) 114 | { 115 | VINFO("EOF"); 116 | pkt->data = nullptr; 117 | pkt->size = 0; 118 | for (auto& it : inputStreams) 119 | { 120 | pkt->stream_index = it.first; 121 | decodePacket(pkt); 122 | it.second->end(); 123 | } 124 | done = true; 125 | return true; 126 | } 127 | // not ready yet 128 | if (ret == AVERROR(EAGAIN)) 129 | { 130 | //VINFO("not ready"); 131 | return true; 132 | } 133 | // error 134 | if (ret < 0) 135 | { 136 | VERRO("failed to read frame: %d", ret); 137 | return false; 138 | } 139 | return decodePacket(pkt); 140 | } 141 | 142 | bool Demuxer::seekKeyFrame(int streamIndex, int64_t nFrame) 143 | { 144 | auto ret = avformat_seek_file(containerContext, 145 | streamIndex, nFrame, nFrame, nFrame, AVSEEK_FLAG_FRAME); 146 | if (ret < 0) 147 | ret = av_seek_frame(containerContext, streamIndex, nFrame, AVSEEK_FLAG_FRAME); 148 | if (ret < 0) 149 | ret = av_seek_frame(containerContext, streamIndex, nFrame, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY); 150 | if (ret < 0) 151 | { 152 | VERRO("failed to seek frame to %d: %d", nFrame, ret); 153 | return false; 154 | } 155 | const auto s = inputStreams.at(streamIndex); 156 | if (s) 157 | { 158 | s->onSeek(); 159 | } 160 | return true; 161 | } 162 | 163 | int Demuxer::getBestAudioStream() 164 | { 165 | if (bestAudioStream < 0) 166 | { 167 | const auto ret = av_find_best_stream( 168 | containerContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0); 169 | if (ret < 0) 170 | return -1; 171 | bestAudioStream = ret; 172 | } 173 | return bestAudioStream; 174 | } 175 | 176 | int Demuxer::getBestVideoStream() 177 | { 178 | if (bestVideoStream < 0) 179 | { 180 | const auto ret = av_find_best_stream( 181 | containerContext, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0); 182 | if (ret < 0) 183 | return -1; 184 | bestVideoStream = ret; 185 | } 186 | return bestVideoStream; 187 | } 188 | 189 | ContainerInfo Demuxer::getInfo() 190 | { 191 | ContainerInfo info; 192 | const auto duration = containerContext->duration + 193 | (containerContext->duration <= INT64_MAX - 5000 ? 5000 : 0); 194 | info.duration = (double)duration / AV_TIME_BASE; 195 | info.start = (double)containerContext->start_time / AV_TIME_BASE; 196 | info.bitRate = containerContext->bit_rate; 197 | info.format = containerContext->iformat; 198 | 199 | for (auto& it : inputStreams) 200 | { 201 | it.second->addToContainerInfo(&info); 202 | } 203 | return info; 204 | } 205 | 206 | FrameReceiver* Demuxer::getFrameReceiver(int streamIndex) 207 | { 208 | const auto s = inputStreams.at(streamIndex); 209 | if(s) 210 | return s->getFrameReceiver(); 211 | return nullptr; 212 | } 213 | 214 | bool Demuxer::decodePacket(AVPacket* pkt) 215 | { 216 | bool ret = true; 217 | auto inputStream = inputStreams.at(pkt->stream_index); 218 | if (inputStream) 219 | ret = inputStream->decodePacket(pkt); 220 | return ret; 221 | } 222 | 223 | bool Demuxer::setReceiver(FrameReceiver* receiver, AVMediaType type, int streamIndex) 224 | { 225 | if (streamIndex < 0) 226 | { 227 | int ret = av_find_best_stream(containerContext, type, -1, -1, nullptr, 0); 228 | if (ret < 0) 229 | { 230 | VERRO("can't find stream in input %s: %d", url.c_str(), ret); 231 | return false; 232 | } 233 | streamIndex = ret; 234 | } 235 | if (streamIndex >= containerContext->nb_streams || 236 | containerContext->streams[streamIndex]->codecpar->codec_type != type) 237 | { 238 | VERRO("invalid stream index"); 239 | return false; 240 | } 241 | auto inputStream = getOrCreateInputStream(streamIndex); 242 | if (!inputStream) 243 | { 244 | VERRO("failed to create input stream"); 245 | return false; 246 | } 247 | inputStream->setFrameReceiver(receiver); 248 | return true; 249 | } 250 | 251 | InputStream* Demuxer::getOrCreateInputStream(int streamIndex) 252 | { 253 | // already exists 254 | if (inputStreams.at(streamIndex)) 255 | return inputStreams.at(streamIndex); 256 | 257 | if (isDone()) 258 | return nullptr; 259 | 260 | const auto stream = containerContext->streams[streamIndex]; 261 | const auto codec_id = stream->codecpar->codec_id; 262 | switch (stream->codecpar->codec_type) 263 | { 264 | case AVMEDIA_TYPE_VIDEO: 265 | { 266 | auto decoder = dynamic_cast(decoders.at(streamIndex)); 267 | if (!decoder) 268 | { 269 | // find hardware decoder first 270 | auto codecs = Codec::getDecoders(AVMEDIA_TYPE_VIDEO, codec_id, true); 271 | if (codecs.empty()) 272 | codecs = Codec::getDecoders(AVMEDIA_TYPE_VIDEO, codec_id); 273 | if (codecs.empty()) 274 | { 275 | VERRO("failed to get codecs for %s", avcodec_get_name(codec_id)); 276 | return nullptr; 277 | } 278 | for (auto& c : codecs) 279 | { 280 | decoder = VideoDecoder::createByName(c->name); 281 | if (decoder) 282 | break; 283 | } 284 | if (!decoder) 285 | { 286 | VERRO("failed to create decoder for %s", avcodec_get_name(codec_id)); 287 | return nullptr; 288 | } 289 | decoders.insert(streamIndex, decoder); 290 | } 291 | // decoder will be opened in InputStream 292 | auto vstream = VideoInputStream::create(decoder, containerContext, stream); 293 | if (!vstream) 294 | { 295 | VERRO("failed to create VideoInputStream"); 296 | return nullptr; 297 | } 298 | inputStreams.insert(streamIndex, vstream); 299 | } 300 | break; 301 | case AVMEDIA_TYPE_AUDIO: 302 | { 303 | auto decoder = dynamic_cast(decoders.at(streamIndex)); 304 | if (!decoder) 305 | { 306 | decoder = AudioDecoder::createById(codec_id); 307 | if (!decoder) 308 | { 309 | VERRO("failed to create decoder for %s", avcodec_get_name(codec_id)); 310 | return nullptr; 311 | } 312 | decoders.insert(streamIndex, decoder); 313 | } 314 | auto astream = AudioInputStream::create(decoder, containerContext, stream); 315 | if(!astream) 316 | { 317 | VERRO("failed to create AudioInputStream"); 318 | return nullptr; 319 | } 320 | inputStreams.insert(streamIndex, astream); 321 | } 322 | break; 323 | default: 324 | break; 325 | } 326 | return inputStreams.at(streamIndex); 327 | } 328 | 329 | void Demuxer::clean() 330 | { 331 | inputStreams.clear(); 332 | decoders.clear(); 333 | } 334 | -------------------------------------------------------------------------------- /FFDemuxer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base/CCRef.h" 3 | #include "base/CCMap.h" 4 | #include "VideoCommon.h" 5 | #include "FFInfo.h" 6 | #include "FFFrameReceiver.h" 7 | #include "FFInputStream.h" 8 | 9 | namespace ffmpeg 10 | { 11 | class Demuxer : public cocos2d::Ref 12 | { 13 | public: 14 | static std::vector getInputFormats(); 15 | protected: 16 | Demuxer(); 17 | virtual ~Demuxer(); 18 | bool init(const std::string& url, AVFormatContext* containerContext); 19 | public: 20 | static Demuxer* create(const std::string& url, AVFormatContext* containerContext); 21 | 22 | bool setAudioReceiver(FrameReceiver* receiver, int streamIndex = -1); 23 | bool setVideoReceiver(FrameReceiver* receiver, int streamIndex = -1); 24 | // prepare will call step, so receiver should be set before it 25 | virtual void prepare(); 26 | virtual bool isDone(); 27 | // step once may or may not give a frame, you need to check receiver outside 28 | virtual bool step(); 29 | virtual bool seekKeyFrame(int streamIndex, int64_t nFrame); 30 | 31 | int getBestAudioStream(); 32 | int getBestVideoStream(); 33 | ContainerInfo getInfo(); 34 | std::string getUrl() const { return url; } 35 | 36 | AVFormatContext* getAVFormatContext() const { return containerContext; } 37 | InputStream* getInputStream(int streamIndex) { return inputStreams.at(streamIndex); } 38 | Decoder* getDecoder(int streamIndex) { return decoders.at(streamIndex); } 39 | FrameReceiver* getFrameReceiver(int streamIndex); 40 | protected: 41 | 42 | bool decodePacket(AVPacket* pkt); 43 | bool setReceiver(FrameReceiver* receiver, AVMediaType type, int streamIndex = -1); 44 | InputStream* getOrCreateInputStream(int index); 45 | void clean(); 46 | 47 | bool done = false; 48 | std::string url; 49 | AVFormatContext* containerContext = nullptr; 50 | int bestAudioStream = -1; 51 | int bestVideoStream = -1; 52 | cocos2d::Map inputStreams; 53 | cocos2d::Map decoders; 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /FFFrameQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "FFFrameQueue.h" 2 | 3 | AVFrame* ffmpeg::FrameQueue::alloc() 4 | { 5 | std::lock_guard lk(mutex); 6 | // only alloc when received because it can be discarded 7 | if(received) 8 | { 9 | queue.push_back(newFramePtr()); 10 | received = false; 11 | } 12 | if (maxSize > 0) 13 | { 14 | while (queue.size() > maxSize) 15 | queue.pop_front(); 16 | } 17 | assert(!queue.empty()); 18 | return queue.back().get(); 19 | } 20 | 21 | void ffmpeg::FrameQueue::receive(AVFrame* frame, MetaData* metaData) 22 | { 23 | assert(!received); 24 | assert(!frame || frame == queue.back().get()); 25 | if(frame) 26 | received = true; 27 | } 28 | 29 | void ffmpeg::FrameQueue::end() 30 | { 31 | } 32 | 33 | void ffmpeg::FrameQueue::clear() 34 | { 35 | std::lock_guard lk(mutex); 36 | queue.clear(); 37 | received = true; 38 | } 39 | 40 | bool ffmpeg::FrameQueue::prepare() 41 | { 42 | return true; 43 | } 44 | 45 | void ffmpeg::FrameQueue::setMaxSize(int size) 46 | { 47 | maxSize = size; 48 | } 49 | 50 | bool ffmpeg::FrameQueue::empty() const 51 | { 52 | if (queue.size() == 1 && !received) 53 | return true; 54 | return queue.empty(); 55 | } 56 | 57 | size_t ffmpeg::FrameQueue::size() const 58 | { 59 | if (queue.size() == 1 && !received) 60 | return 0; 61 | return queue.size(); 62 | } 63 | 64 | ffmpeg::frame_ptr ffmpeg::FrameQueue::pop() 65 | { 66 | std::lock_guard lk(mutex); 67 | if (queue.empty()) 68 | return nullptr; 69 | // not ready to use 70 | if (queue.size() == 1 && !received) 71 | return nullptr; 72 | auto f = std::move(queue.front()); 73 | queue.pop_front(); 74 | return f; 75 | } 76 | 77 | ffmpeg::AudioFrameQueue* ffmpeg::AudioFrameQueue::create() 78 | { 79 | auto ret = new (std::nothrow) AudioFrameQueue(); 80 | if (ret) 81 | { 82 | ret->autorelease(); 83 | return ret; 84 | } 85 | delete ret; 86 | return nullptr; 87 | } 88 | 89 | ffmpeg::VideoFrameQueue* ffmpeg::VideoFrameQueue::create() 90 | { 91 | auto ret = new (std::nothrow) VideoFrameQueue(); 92 | if (ret) 93 | { 94 | ret->autorelease(); 95 | return ret; 96 | } 97 | delete ret; 98 | return nullptr; 99 | } 100 | -------------------------------------------------------------------------------- /FFFrameQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base/CCRef.h" 3 | #include "VideoCommon.h" 4 | #include "FFFrameReceiver.h" 5 | #include "FFPointer.h" 6 | #include 7 | #include 8 | 9 | namespace ffmpeg 10 | { 11 | class FrameQueue : public FrameReceiver 12 | { 13 | protected: 14 | FrameQueue() = default; 15 | virtual ~FrameQueue() = default; 16 | public: 17 | AVFrame* alloc() override; 18 | void receive(AVFrame* frame, MetaData* metaData) override; 19 | void end() override; 20 | void clear() override; 21 | bool prepare() override; 22 | 23 | void setMaxSize(int size); 24 | bool empty() const; 25 | size_t size() const; 26 | frame_ptr pop(); 27 | 28 | protected: 29 | std::deque queue; 30 | std::mutex mutex; 31 | int maxSize = -1; 32 | bool received = true; 33 | }; 34 | 35 | class AudioFrameQueue : public FrameQueue 36 | { 37 | protected: 38 | AudioFrameQueue() = default; 39 | virtual ~AudioFrameQueue() = default; 40 | public: 41 | static AudioFrameQueue* create(); 42 | AVMediaType getMediaType() override { return AVMEDIA_TYPE_AUDIO; } 43 | }; 44 | 45 | class VideoFrameQueue : public FrameQueue 46 | { 47 | protected: 48 | VideoFrameQueue() = default; 49 | virtual ~VideoFrameQueue() = default; 50 | public: 51 | static VideoFrameQueue* create(); 52 | AVMediaType getMediaType() override { return AVMEDIA_TYPE_VIDEO; } 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /FFFrameReceiver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base/CCRef.h" 3 | #include "VideoCommon.h" 4 | #include "FFInfo.h" 5 | 6 | namespace ffmpeg 7 | { 8 | class FrameReceiver : public cocos2d::Ref 9 | { 10 | public: 11 | virtual ~FrameReceiver() = default; 12 | // give frame for next receive, return nullptr will use sender's frame 13 | virtual AVFrame* alloc() = 0; 14 | virtual void receive(AVFrame* frame, MetaData* metaData) = 0; 15 | // called at EOF 16 | virtual void end() = 0; 17 | // clear internal buffer 18 | virtual void clear() = 0; 19 | /** 20 | * Return whether we have all information we need to start receiving data. 21 | * A container might only be primed once it received at least one frame from each source 22 | * it will be muxing together. 23 | */ 24 | virtual bool prepare() = 0; 25 | virtual AVMediaType getMediaType() = 0; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /FFHardware.cpp: -------------------------------------------------------------------------------- 1 | #include "FFHardware.h" 2 | 3 | using namespace ffmpeg; 4 | 5 | AVPixelFormat Hardware::targetFormat = AV_PIX_FMT_NONE; 6 | 7 | AVPixelFormat Hardware::getFormat(AVCodecContext* ctx, const AVPixelFormat* pix_fmts) 8 | { 9 | for (auto p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) 10 | { 11 | if (*p == targetFormat) 12 | return *p; 13 | } 14 | return AV_PIX_FMT_NONE; 15 | } 16 | 17 | std::vector Hardware::getDeviceTypes() 18 | { 19 | std::vector ret; 20 | auto type = AV_HWDEVICE_TYPE_NONE; 21 | while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) 22 | ret.push_back(type); 23 | return ret; 24 | } 25 | 26 | bool Hardware::isSupported(AVCodec* codec) 27 | { 28 | return codec && avcodec_get_hw_config(codec, 0); 29 | } 30 | 31 | bool Hardware::isSupported(AVCodec* codec, AVHWDeviceType type) 32 | { 33 | auto types = getSupportedDeviceTypes(codec); 34 | for (auto& t : types) 35 | { 36 | if (t == type) 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | std::vector Hardware::getSupportedDeviceTypes(AVCodec* codec) 43 | { 44 | std::vector ret; 45 | if (codec) 46 | { 47 | for (auto i = 0;; i++) 48 | { 49 | auto config = avcodec_get_hw_config(codec, i); 50 | if(!config) 51 | break; 52 | if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) 53 | { 54 | ret.push_back(config->device_type); 55 | } 56 | } 57 | } 58 | return ret; 59 | } 60 | 61 | std::vector Hardware::getConfigs(AVCodec* codec) 62 | { 63 | std::vector ret; 64 | if (codec) 65 | { 66 | for (auto i = 0;; i++) 67 | { 68 | auto config = avcodec_get_hw_config(codec, i); 69 | if (!config) 70 | break; 71 | ret.push_back(config); 72 | } 73 | } 74 | return ret; 75 | } 76 | 77 | AVBufferRef* Hardware::createDeviceContext(AVCodecContext* codecCtx, const AVCodecHWConfig* config) 78 | { 79 | if (!codecCtx || !config || !(config->methods&AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) 80 | return nullptr; 81 | targetFormat = config->pix_fmt; 82 | codecCtx->get_format = getFormat; 83 | AVBufferRef* hw_device_ctx; 84 | int err; 85 | if ((err = av_hwdevice_ctx_create(&hw_device_ctx, 86 | config->device_type, nullptr, nullptr, 0)) < 0) 87 | { 88 | return nullptr; 89 | } 90 | codecCtx->hw_device_ctx = av_buffer_ref(hw_device_ctx); 91 | return hw_device_ctx; 92 | } 93 | 94 | AVPixelFormat Hardware::getHardwareFormat(const AVCodecHWConfig* config) 95 | { 96 | if (config) 97 | return config->pix_fmt; 98 | return AV_PIX_FMT_NONE; 99 | } 100 | 101 | std::vector Hardware::getSoftwareFormats(AVBufferRef* deviceCtx) 102 | { 103 | std::vector ret; 104 | if (deviceCtx) 105 | { 106 | auto constraints = av_hwdevice_get_hwframe_constraints(deviceCtx, nullptr); 107 | if (!constraints || !constraints->valid_sw_formats) 108 | return ret; 109 | for (auto p = constraints->valid_sw_formats; *p != AV_PIX_FMT_NONE; p++) 110 | { 111 | ret.push_back(*p); 112 | } 113 | } 114 | return ret; 115 | } 116 | -------------------------------------------------------------------------------- /FFHardware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "VideoCommon.h" 3 | #include 4 | 5 | namespace ffmpeg 6 | { 7 | class Hardware 8 | { 9 | static AVPixelFormat targetFormat; 10 | static AVPixelFormat getFormat(AVCodecContext* ctx, const AVPixelFormat* pix_fmts); 11 | public: 12 | static std::vector getDeviceTypes(); 13 | static bool isSupported(AVCodec* codec); 14 | static bool isSupported(AVCodec* codec, AVHWDeviceType type); 15 | static std::vector getSupportedDeviceTypes(AVCodec* codec); 16 | static std::vector getConfigs(AVCodec* codec); 17 | // call before avcodec_open2 18 | static AVBufferRef* createDeviceContext(AVCodecContext* codecCtx, const AVCodecHWConfig* config); 19 | static AVPixelFormat getHardwareFormat(const AVCodecHWConfig* config); 20 | static std::vector getSoftwareFormats(AVBufferRef* deviceCtx); 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /FFInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "VideoCommon.h" 3 | #include 4 | 5 | namespace ffmpeg 6 | { 7 | struct VideoStreamInfo 8 | { 9 | int index; 10 | int id; 11 | int64_t numFrames; 12 | AVRational frameRate; 13 | AVRational timeBase; 14 | const AVCodec* codec; 15 | // bits per second 16 | int64_t bitRate; 17 | 18 | AVPixelFormat format; 19 | const char* formatName; 20 | 21 | int width, height; 22 | }; 23 | 24 | struct AudioStreamInfo 25 | { 26 | int index; 27 | int id; 28 | int64_t numFrames; 29 | AVRational timeBase; 30 | const AVCodec* codec; 31 | // bits per second 32 | int64_t bitRate; 33 | 34 | int sampleRate; 35 | int channels; 36 | 37 | uint64_t channelLayout; 38 | char channelLayoutName[255]; 39 | }; 40 | 41 | struct ContainerInfo 42 | { 43 | // in seconds 44 | double duration; 45 | // start time in seconds 46 | double start; 47 | // bits per second 48 | int64_t bitRate; 49 | const AVInputFormat* format; 50 | 51 | std::vector videoStreams; 52 | std::vector audioStreams; 53 | }; 54 | 55 | struct MetaData 56 | { 57 | AVMediaType type; 58 | AVRational timeBase; 59 | AVRational frameRate; 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /FFInputStream.cpp: -------------------------------------------------------------------------------- 1 | #include "FFInputStream.h" 2 | #include "FFInfo.h" 3 | #include 4 | 5 | using namespace std; 6 | using namespace ffmpeg; 7 | 8 | InputStream::InputStream() 9 | { 10 | } 11 | 12 | InputStream::~InputStream() 13 | { 14 | InputStream::clean(); 15 | } 16 | 17 | bool InputStream::init(Decoder* decoder, AVFormatContext* format, AVStream* stream) 18 | { 19 | if (!decoder || !format || !stream) 20 | { 21 | return false; 22 | } 23 | this->stream = stream; 24 | this->format = format; 25 | this->decoder = decoder; 26 | CC_SAFE_RETAIN(decoder); 27 | 28 | auto codec = decoder->getCodec(); 29 | codecContext = decoder->getCodecContext(); 30 | //codecContext->framerate = stream->avg_frame_rate; 31 | 32 | int ret; 33 | if ((ret = avcodec_parameters_to_context(codecContext, stream->codecpar)) < 0) 34 | { 35 | VERRO("failed to get parameters of codec %s: %d", codec->name, ret); 36 | return false; 37 | } 38 | 39 | // configure before open 40 | configureCodecContext(); 41 | 42 | if (!decoder->open()) 43 | { 44 | VERRO("failed to open codec %s: %d", codec->name, ret); 45 | return false; 46 | } 47 | 48 | if (!codecContext->codec) 49 | codecContext->codec = codec; 50 | 51 | // calculate the "correct" time_base 52 | timeBaseCorrectedByTicksPerFrame.num = codecContext->time_base.num; 53 | timeBaseCorrectedByTicksPerFrame.den = codecContext->time_base.den; 54 | timeBaseCorrectedByTicksPerFrame.num *= codecContext->ticks_per_frame; 55 | 56 | // temperary frame 57 | frame = av_frame_alloc(); 58 | if (!frame) 59 | { 60 | VERRO("can't allocate frame"); 61 | return false; 62 | } 63 | return true; 64 | } 65 | 66 | void InputStream::setFrameReceiver(FrameReceiver* newReceiver) 67 | { 68 | CC_SAFE_RELEASE_NULL(receiver); 69 | receiver = newReceiver; 70 | CC_SAFE_RETAIN(receiver); 71 | } 72 | 73 | void InputStream::end() 74 | { 75 | if (receiver) 76 | receiver->end(); 77 | } 78 | 79 | bool InputStream::prepare() 80 | { 81 | if (receiver) 82 | return receiver->prepare(); 83 | return true; 84 | } 85 | 86 | void InputStream::onSeek() 87 | { 88 | if (receiver) 89 | receiver->clear(); 90 | decoder->flushBuffers(); 91 | } 92 | 93 | bool InputStream::decodePacket(AVPacket* pkt) 94 | { 95 | if(!sendPacket(pkt)) 96 | return false; 97 | 98 | int ret = 0; 99 | // receive all output frames 100 | while (ret >= 0) 101 | { 102 | AVFrame* tmpFrame = nullptr; 103 | if (receiver) 104 | tmpFrame = receiver->alloc(); 105 | if (!tmpFrame) 106 | tmpFrame = frame; 107 | 108 | ret = avcodec_receive_frame(codecContext, tmpFrame); 109 | if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) 110 | return true; 111 | if (ret < 0) 112 | { 113 | auto err = video::getErrorString(ret); 114 | if (ret == AVERROR(EINVAL)) 115 | err = "the decoder is invalid"; 116 | VERRO("failed to receive frame: %s", err.c_str()); 117 | return false; 118 | } 119 | 120 | // put default settings from the stream into the frame 121 | if (!tmpFrame->sample_aspect_ratio.num) 122 | tmpFrame->sample_aspect_ratio = stream->sample_aspect_ratio; 123 | 124 | if (!metaData) 125 | discoverMetaData(); 126 | 127 | if (receiver) 128 | { 129 | receiver->receive(tmpFrame, metaData); 130 | } 131 | } 132 | return true; 133 | } 134 | 135 | bool InputStream::sendPacket(AVPacket* pkt) 136 | { 137 | const auto ret = avcodec_send_packet(codecContext, pkt); 138 | if (ret >= 0) 139 | return true; 140 | if (ret == AVERROR_EOF) 141 | { 142 | // the decoder has been flushed 143 | return true; 144 | } 145 | auto err = video::getErrorString(ret); 146 | if (ret == AVERROR(EAGAIN)) 147 | err = "input is not accepted in the current state"; 148 | else if (ret == AVERROR(EINVAL)) 149 | err = "the decoder is invalid"; 150 | else if (ret == AVERROR(ENOMEM)) 151 | err = "failed to add packet to internal queue"; 152 | VERRO("failed to send packet: %s", err.c_str()); 153 | return false; 154 | } 155 | 156 | void InputStream::configureCodecContext() 157 | { 158 | } 159 | 160 | int64_t InputStream::calculateBitRate(AVCodecContext* ctx) 161 | { 162 | int64_t bit_rate; 163 | int bits_per_sample; 164 | 165 | switch (ctx->codec_type) 166 | { 167 | case AVMEDIA_TYPE_VIDEO: 168 | case AVMEDIA_TYPE_DATA: 169 | case AVMEDIA_TYPE_SUBTITLE: 170 | case AVMEDIA_TYPE_ATTACHMENT: 171 | bit_rate = ctx->bit_rate; 172 | break; 173 | case AVMEDIA_TYPE_AUDIO: 174 | bits_per_sample = av_get_bits_per_sample(ctx->codec_id); 175 | bit_rate = bits_per_sample ? 176 | ctx->sample_rate * (int64_t)ctx->channels * bits_per_sample : ctx->bit_rate; 177 | break; 178 | default: 179 | bit_rate = 0; 180 | break; 181 | } 182 | return bit_rate; 183 | } 184 | 185 | void InputStream::discoverMetaData() 186 | { 187 | AVRational overrideFrameRate; 188 | overrideFrameRate.num = 0; 189 | overrideFrameRate.den = 0; 190 | 191 | AVRational tb = overrideFrameRate.num ? 192 | av_inv_q(overrideFrameRate) : stream->time_base; 193 | AVRational fr = overrideFrameRate; 194 | if (!fr.num) 195 | fr = av_guess_frame_rate(format, stream, nullptr); 196 | 197 | if (!metaData) 198 | metaData = new MetaData(); 199 | metaData->timeBase = tb; 200 | metaData->frameRate = fr; 201 | metaData->type = codecContext->codec->type; 202 | } 203 | 204 | void InputStream::clean() 205 | { 206 | if (frame) 207 | { 208 | av_frame_free(&frame); 209 | frame = nullptr; 210 | } 211 | if (metaData) 212 | { 213 | delete metaData; 214 | metaData = nullptr; 215 | } 216 | CC_SAFE_RELEASE_NULL(receiver); 217 | CC_SAFE_RELEASE_NULL(decoder); 218 | } 219 | 220 | VideoInputStream::~VideoInputStream() 221 | { 222 | VideoInputStream::clean(); 223 | } 224 | 225 | VideoInputStream* VideoInputStream::create( 226 | VideoDecoder* decoder, AVFormatContext* format, AVStream* stream) 227 | { 228 | auto ret = new (std::nothrow) VideoInputStream(); 229 | if (ret && ret->init(decoder, format, stream)) 230 | { 231 | ret->frameSW = av_frame_alloc(); 232 | ret->autorelease(); 233 | return ret; 234 | } 235 | delete ret; 236 | return nullptr; 237 | } 238 | 239 | bool VideoInputStream::decodePacket(AVPacket* pkt) 240 | { 241 | if (!sendPacket(pkt)) 242 | return false; 243 | 244 | auto decoder_ = dynamic_cast(decoder); 245 | const auto is_hw = decoder_->isHardware(); 246 | const auto hw_fmt = decoder_->getHardwareFormat(); 247 | 248 | int ret = 0; 249 | while (ret >= 0) 250 | { 251 | AVFrame* tmpFrame = nullptr; 252 | AVFrame* tmpFrameSW = nullptr; 253 | if (is_hw) 254 | { 255 | tmpFrame = frame; 256 | if (receiver) 257 | tmpFrameSW = receiver->alloc(); 258 | else 259 | tmpFrameSW = frameSW; 260 | } 261 | else 262 | { 263 | if (receiver) 264 | tmpFrame = receiver->alloc(); 265 | if (!tmpFrame) 266 | tmpFrame = frame; 267 | } 268 | 269 | ret = avcodec_receive_frame(codecContext, tmpFrame); 270 | if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) 271 | return true; 272 | if (ret < 0) 273 | { 274 | VERRO("Error during decoding: %d", ret); 275 | return false; 276 | } 277 | if (is_hw && tmpFrame->format == hw_fmt) 278 | { 279 | ret = av_hwframe_transfer_data(tmpFrameSW, tmpFrame, 0); 280 | if (ret < 0) 281 | { 282 | VERRO("failed to transfer hw data: %d", ret); 283 | return false; 284 | } 285 | av_frame_copy_props(tmpFrameSW, tmpFrame); 286 | tmpFrame = tmpFrameSW; 287 | } 288 | 289 | // put default settings from the stream into the frame 290 | if (!tmpFrame->sample_aspect_ratio.num) 291 | { 292 | tmpFrame->sample_aspect_ratio = stream->sample_aspect_ratio; 293 | } 294 | 295 | if (!metaData) 296 | discoverMetaData(); 297 | 298 | if (receiver) 299 | { 300 | receiver->receive(tmpFrame, metaData); 301 | } 302 | } 303 | return true; 304 | } 305 | 306 | void VideoInputStream::addToContainerInfo(ContainerInfo* containerInfo) 307 | { 308 | VideoStreamInfo info{}; 309 | 310 | info.index = stream->index; 311 | info.id = stream->id; 312 | info.numFrames = stream->nb_frames; 313 | info.timeBase = stream->time_base; 314 | 315 | auto fr = stream->avg_frame_rate; 316 | if (!fr.num || !fr.den) 317 | fr = av_guess_frame_rate(format, stream, nullptr); 318 | 319 | info.frameRate = fr; 320 | 321 | auto codecContext = decoder->getCodecContext(); 322 | 323 | //codecContext->properties = stream->codec->properties; 324 | //codecContext->codec = stream->codec->codec; 325 | //codecContext->qmin = stream->codec->qmin; 326 | //codecContext->qmax = stream->codec->qmax; 327 | //codecContext->coded_width = stream->codec->coded_width; 328 | //codecContext->coded_height = stream->codec->coded_height; 329 | 330 | info.bitRate = calculateBitRate(codecContext); 331 | 332 | info.codec = avcodec_find_decoder(codecContext->codec_id); 333 | info.format = codecContext->pix_fmt; 334 | info.formatName = av_get_pix_fmt_name(info.format); 335 | info.width = codecContext->width; 336 | info.height = codecContext->height; 337 | containerInfo->videoStreams.push_back(info); 338 | } 339 | 340 | void VideoInputStream::configureCodecContext() 341 | { 342 | } 343 | 344 | void VideoInputStream::clean() 345 | { 346 | InputStream::clean(); 347 | if (frameSW) 348 | { 349 | av_frame_free(&frameSW); 350 | frameSW = nullptr; 351 | } 352 | } 353 | 354 | AudioInputStream* AudioInputStream::create( 355 | AudioDecoder* decoder, AVFormatContext* format, AVStream* stream) 356 | { 357 | auto ret = new (std::nothrow) AudioInputStream(); 358 | if (ret && ret->init(decoder, format, stream)) 359 | { 360 | ret->autorelease(); 361 | return ret; 362 | } 363 | delete ret; 364 | return nullptr; 365 | } 366 | 367 | void AudioInputStream::addToContainerInfo(ContainerInfo* containerInfo) 368 | { 369 | AudioStreamInfo info{}; 370 | 371 | info.index = stream->index; 372 | info.id = stream->id; 373 | info.numFrames = stream->nb_frames; 374 | info.timeBase = stream->time_base; 375 | 376 | auto codecContext = decoder->getCodecContext(); 377 | 378 | //codecContext->properties = stream->codec->properties; 379 | //codecContext->codec = stream->codec->codec; 380 | //codecContext->qmin = stream->codec->qmin; 381 | //codecContext->qmax = stream->codec->qmax; 382 | //codecContext->coded_width = stream->codec->coded_width; 383 | //codecContext->coded_height = stream->codec->coded_height; 384 | 385 | info.bitRate = calculateBitRate(codecContext); 386 | 387 | info.codec = avcodec_find_decoder(codecContext->codec_id); 388 | info.sampleRate = codecContext->sample_rate; 389 | info.channels = codecContext->channels; 390 | info.channelLayout = codecContext->channel_layout; 391 | std::memset(info.channelLayoutName, 0, sizeof(info.channelLayoutName)); 392 | av_get_channel_layout_string(info.channelLayoutName, 255, codecContext->channels, codecContext->channel_layout); 393 | containerInfo->audioStreams.push_back(info); 394 | } 395 | 396 | void AudioInputStream::configureCodecContext() 397 | { 398 | // guess channel layout for the decoder 399 | if (!codecContext->channel_layout) 400 | { 401 | codecContext->channel_layout = av_get_default_channel_layout(codecContext->channels); 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /FFInputStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base/CCRef.h" 3 | #include "VideoCommon.h" 4 | #include "FFInfo.h" 5 | #include "FFFrameReceiver.h" 6 | #include "FFCodec.h" 7 | 8 | namespace ffmpeg 9 | { 10 | struct ContainerInfo; 11 | 12 | class InputStream : public cocos2d::Ref 13 | { 14 | protected: 15 | InputStream(); 16 | virtual ~InputStream(); 17 | bool init(Decoder* decoder, AVFormatContext* format, AVStream* stream); 18 | public: 19 | void setFrameReceiver(FrameReceiver* newReceiver); 20 | FrameReceiver* getFrameReceiver() const { return receiver; } 21 | void end(); 22 | bool prepare(); 23 | void onSeek(); 24 | virtual void addToContainerInfo(ContainerInfo* info) = 0; 25 | 26 | Decoder* getDecoder() const { return decoder; } 27 | AVStream* getStream() const { return stream; } 28 | 29 | virtual bool decodePacket(AVPacket* pkt); 30 | protected: 31 | virtual bool sendPacket(AVPacket* pkt); 32 | 33 | virtual void configureCodecContext(); 34 | static int64_t calculateBitRate(AVCodecContext* ctx); 35 | void discoverMetaData(); 36 | virtual void clean(); 37 | 38 | AVCodecContext* codecContext = nullptr; 39 | AVFormatContext* format = nullptr; 40 | AVStream* stream = nullptr; 41 | 42 | AVRational timeBaseCorrectedByTicksPerFrame; 43 | FrameReceiver* receiver = nullptr; 44 | Decoder* decoder = nullptr; 45 | AVFrame* frame = nullptr; 46 | MetaData* metaData = nullptr; 47 | }; 48 | 49 | class VideoInputStream : public InputStream 50 | { 51 | virtual ~VideoInputStream(); 52 | public: 53 | static VideoInputStream* create( 54 | VideoDecoder* decoder, AVFormatContext* format, AVStream* stream); 55 | bool decodePacket(AVPacket* pkt) override; 56 | void addToContainerInfo(ContainerInfo* info) override; 57 | protected: 58 | void configureCodecContext() override; 59 | void clean() override; 60 | AVFrame* frameSW = nullptr; 61 | }; 62 | 63 | class AudioInputStream : public InputStream 64 | { 65 | virtual ~AudioInputStream() = default; 66 | public: 67 | static AudioInputStream* create( 68 | AudioDecoder* decoder, AVFormatContext* format, AVStream* stream); 69 | void addToContainerInfo(ContainerInfo* info) override; 70 | protected: 71 | void configureCodecContext() override; 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /FFPointer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "VideoCommon.h" 3 | #include 4 | 5 | namespace ffmpeg 6 | { 7 | using packet_ptr = std::unique_ptr>; 8 | inline packet_ptr newPacketPtr() 9 | { 10 | return packet_ptr{ 11 | new AVPacket, [](AVPacket* p) { av_packet_unref(p); delete p; } }; 12 | } 13 | 14 | using frame_ptr = std::unique_ptr>; 15 | inline frame_ptr newFramePtr() 16 | { 17 | return frame_ptr{ 18 | av_frame_alloc(), [](AVFrame* p) { av_frame_free(&p); } }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Xrysnow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cocos2d-x-video 2 | 3 | This project is video support for [cocos2d-x](https://github.com/cocos2d/cocos2d-x) based on [ffmpeg](https://ffmpeg.org/). 4 | 5 | It has many limits and only supports basic playback. 6 | 7 | ## Dependencies 8 | 9 | * [cocos2d-x](https://github.com/cocos2d/cocos2d-x) 4.0+ 10 | * [ffmpeg](https://ffmpeg.org/) 4.0+ 11 | -------------------------------------------------------------------------------- /VideoCommon.cpp: -------------------------------------------------------------------------------- 1 | #include "VideoCommon.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace video; 7 | 8 | namespace 9 | { 10 | std::function VideoLoggingFunction; 11 | } 12 | 13 | void video::setLoggingFunction(const std::function& callback) 14 | { 15 | VideoLoggingFunction = callback; 16 | } 17 | 18 | void video::logging(const char* format, ...) 19 | { 20 | if (!VideoLoggingFunction) 21 | return; 22 | constexpr auto BUFFER_LENGTH = 512; 23 | va_list args; 24 | std::string buffer(BUFFER_LENGTH, '\0'); 25 | 26 | va_start(args, format); 27 | int nret = vsnprintf(&buffer.front(), buffer.length() + 1, format, args); 28 | va_end(args); 29 | 30 | if (nret >= 0) { 31 | if ((unsigned int)nret < buffer.length()) { 32 | buffer.resize(nret); 33 | } 34 | else if ((unsigned int)nret > buffer.length()) { // VS2015/2017 or later Visual Studio Version 35 | buffer.resize(nret); 36 | 37 | va_start(args, format); 38 | nret = vsnprintf(&buffer.front(), buffer.length() + 1, format, args); 39 | va_end(args); 40 | 41 | assert(nret == buffer.length()); 42 | } 43 | // else equals, do nothing. 44 | } 45 | else { // less or equal VS2013 and Unix System glibc implement. 46 | do { 47 | buffer.resize(buffer.length() * 3 / 2); 48 | 49 | va_start(args, format); 50 | nret = vsnprintf(&buffer.front(), buffer.length() + 1, format, args); 51 | va_end(args); 52 | 53 | } while (nret < 0); 54 | 55 | buffer.resize(nret); 56 | } 57 | VideoLoggingFunction(buffer); 58 | } 59 | 60 | std::string video::getErrorString(int errorCode) 61 | { 62 | constexpr size_t size = 64; 63 | char buffer[size]; 64 | av_make_error_string(buffer, size, errorCode); 65 | return std::string(buffer); 66 | } 67 | -------------------------------------------------------------------------------- /VideoCommon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/CCPlatformConfig.h" 3 | #include 4 | #include 5 | 6 | namespace video 7 | { 8 | void setLoggingFunction(const std::function& callback); 9 | void logging(const char* format, ...); 10 | std::string getErrorString(int errorCode); 11 | } 12 | 13 | #define VINFO(_str, ...) video::logging("[VINFO] [%s] " _str, __FUNCTION__, ##__VA_ARGS__) 14 | #define VWARN(_str,...) video::logging("[VWARN] [%s] " _str, __FUNCTION__, ##__VA_ARGS__) 15 | #define VERRO(_str, ...) video::logging("[VERRO] [%s] " _str, __FUNCTION__, ##__VA_ARGS__) 16 | 17 | extern "C" 18 | { 19 | #include "libavformat/avformat.h" 20 | #include "libavformat/avio.h" 21 | #include "libavcodec/avcodec.h" 22 | #include "libswscale/swscale.h" 23 | #include "libswresample/swresample.h" 24 | 25 | #include "libavutil/frame.h" 26 | #include "libavutil/mem.h" 27 | #include "libavutil/file.h" 28 | #include "libavutil/common.h" 29 | #include "libavutil/rational.h" 30 | #include "libavutil/avutil.h" 31 | #include "libavutil/imgutils.h" 32 | #include "libavutil/opt.h" 33 | } 34 | -------------------------------------------------------------------------------- /VideoDecoder.cpp: -------------------------------------------------------------------------------- 1 | #include "VideoDecoder.h" 2 | 3 | using namespace std; 4 | using namespace cocos2d; 5 | using namespace video; 6 | 7 | Decoder* Decoder::create(const std::string& path) 8 | { 9 | auto ret = new (std::nothrow) Decoder(); 10 | if (ret&&ret->open(path)) 11 | { 12 | ret->autorelease(); 13 | return ret; 14 | } 15 | delete ret; 16 | return nullptr; 17 | } 18 | 19 | bool Decoder::open(const std::string& path) 20 | { 21 | if (opened) 22 | return false; 23 | filePath = FileUtils::getInstance()->fullPathForFilename(path); 24 | if (filePath.empty()) 25 | { 26 | VERRO("no file: %s", path.c_str()); 27 | return false; 28 | } 29 | 30 | bool ok = false; 31 | #define BREAK_IF(cond) if(cond) { VINFO("failed: %s", #cond); break; } 32 | do 33 | { 34 | pFormatCtx = avformat_alloc_context(); 35 | BREAK_IF(!pFormatCtx); 36 | demuxer = ffmpeg::Demuxer::create(filePath, pFormatCtx); 37 | BREAK_IF(!demuxer); 38 | demuxer->retain(); 39 | 40 | idxAudio = demuxer->getBestAudioStream(); 41 | idxVideo = demuxer->getBestVideoStream(); 42 | BREAK_IF(idxVideo < 0); 43 | 44 | videoQueue = ffmpeg::VideoFrameQueue::create(); 45 | BREAK_IF(!videoQueue); 46 | videoQueue->retain(); 47 | videoQueue->setMaxSize(64); 48 | BREAK_IF(!demuxer->setVideoReceiver(videoQueue, idxVideo)); 49 | if (idxAudio >= 0) 50 | { 51 | audioQueue = ffmpeg::AudioFrameQueue::create(); 52 | BREAK_IF(!audioQueue); 53 | audioQueue->retain(); 54 | audioQueue->setMaxSize(64); 55 | demuxer->setAudioReceiver(audioQueue, idxAudio); 56 | } 57 | 58 | demuxer->prepare(); 59 | 60 | BREAK_IF(!demuxer->getDecoder(idxVideo)); 61 | 62 | // get the codec context for the video stream 63 | pCodecCtx = demuxer->getDecoder(idxVideo)->getCodecContext(); 64 | pCodecV = demuxer->getDecoder(idxVideo)->getCodec(); 65 | 66 | ok = true; 67 | } 68 | while (false); 69 | 70 | if (!ok) 71 | return false; 72 | 73 | //av_dump_format(pFormatCtx, 0, filePath.c_str(), 0); 74 | 75 | nFramesV = pFormatCtx->streams[idxVideo]->nb_frames; 76 | rawWidth = pCodecCtx->width; 77 | rawHeight = pCodecCtx->height; 78 | timeBaseV = pFormatCtx->streams[idxVideo]->time_base; 79 | if (idxAudio >= 0) 80 | timeBaseA = pFormatCtx->streams[idxAudio]->time_base; 81 | durationV = pFormatCtx->streams[idxVideo]->duration * av_q2d(timeBaseV); 82 | 83 | videoInfo = demuxer->getInfo(); 84 | for (int i = 0; i < videoInfo.videoStreams.size(); ++i) 85 | { 86 | if (videoInfo.videoStreams.at(i).index == idxVideo) 87 | idxVideoAtInfo = i; 88 | } 89 | for (int i = 0; i < videoInfo.audioStreams.size(); ++i) 90 | { 91 | if (videoInfo.audioStreams.at(i).index == idxAudio) 92 | idxAudioAtInfo = i; 93 | } 94 | opened = true; 95 | return true; 96 | } 97 | 98 | bool Decoder::open(VideoStream* stream_, double loopA, double loopB) 99 | { 100 | if (opened || !stream_) 101 | return false; 102 | //TODO: 103 | return true; 104 | } 105 | 106 | bool Decoder::setup() 107 | { 108 | return setup(Size(rawWidth, rawHeight)); 109 | } 110 | 111 | bool Decoder::setup(const Size& target_size) 112 | { 113 | if (img_convert_ctx) 114 | { 115 | // already setup 116 | return false; 117 | } 118 | const int width = (int)target_size.width; 119 | const int height = (int)target_size.height; 120 | if (width <= 0 || height <= 0) 121 | { 122 | return false; 123 | } 124 | targetSize = Size(width, height); 125 | // TODO: avoid sws 126 | auto ret = av_image_alloc(sws_pointers, sws_linesizes, 127 | width, height, swsFormat, 1); 128 | if (ret < 0) 129 | { 130 | VERRO("can't alloc image"); 131 | return false; 132 | } 133 | auto dec = (ffmpeg::VideoDecoder*)demuxer->getDecoder(idxVideo); 134 | auto srcFormat = pCodecCtx->pix_fmt; 135 | if (dec->isHardware()) 136 | srcFormat = dec->getSoftwareFormat(); 137 | CC_ASSERT(srcFormat >= 0); 138 | // scale/convert 139 | img_convert_ctx = sws_getContext( 140 | pCodecCtx->width, 141 | pCodecCtx->height, 142 | srcFormat, 143 | width, 144 | height, 145 | swsFormat, 146 | SWS_FAST_BILINEAR, 147 | nullptr, nullptr, nullptr); 148 | VINFO("image conversion: %s(%dx%d) -> %s(%dx%d)", 149 | av_pix_fmt_desc_get(srcFormat)->name, 150 | pCodecCtx->width, 151 | pCodecCtx->height, 152 | av_pix_fmt_desc_get(swsFormat)->name, 153 | width, 154 | height); 155 | if (!img_convert_ctx) 156 | { 157 | VERRO("can't create sws context"); 158 | return false; 159 | } 160 | return true; 161 | } 162 | 163 | bool Decoder::isOpened() const 164 | { 165 | return opened; 166 | } 167 | 168 | void Decoder::close() 169 | { 170 | CC_SAFE_RELEASE_NULL(videoQueue); 171 | CC_SAFE_RELEASE_NULL(audioQueue); 172 | CC_SAFE_RELEASE_NULL(demuxer); 173 | if(img_convert_ctx) 174 | { 175 | sws_freeContext(img_convert_ctx); 176 | img_convert_ctx = nullptr; 177 | } 178 | if (sws_pointers[0]) 179 | { 180 | av_freep(&sws_pointers[0]); 181 | memset(sws_pointers, 0, sizeof(void*) * 4); 182 | } 183 | if (stream) 184 | { 185 | stream->release(); 186 | stream = nullptr; 187 | } 188 | if (pFormatCtx) 189 | { 190 | avformat_free_context(pFormatCtx); 191 | pFormatCtx = nullptr; 192 | } 193 | opened = false; 194 | } 195 | 196 | uint32_t Decoder::read(uint8_t** vbuf) 197 | { 198 | *vbuf = nullptr; 199 | if (currentFrame == (nFramesV - 1) || !opened) 200 | return 0; 201 | if (lastFrame == currentFrame) 202 | { 203 | if(vFrame) 204 | *vbuf = sws_pointers[0]; 205 | return 0; 206 | } 207 | 208 | //bool ok = true; 209 | while (videoQueue->empty()) 210 | { 211 | if (!demuxer->step()) 212 | { 213 | //ok = false; 214 | break; 215 | } 216 | } 217 | 218 | if (videoQueue->empty()) 219 | return 0; 220 | 221 | vFrame = videoQueue->pop(); 222 | CC_ASSERT(vFrame); 223 | 224 | sws_scale(img_convert_ctx, 225 | vFrame->data, vFrame->linesize, 226 | 0, pCodecCtx->height, 227 | sws_pointers, sws_linesizes); 228 | lastFrame = currentFrame; 229 | currentFrame++; 230 | *vbuf = sws_pointers[0]; 231 | return 1; 232 | } 233 | 234 | AVPixelFormat Decoder::getReadFormat() 235 | { 236 | return swsFormat; 237 | } 238 | 239 | bool Decoder::seek(int64_t frameOffset) 240 | { 241 | if (!opened || frameOffset >= nFramesV || frameOffset < 0) 242 | return false; 243 | if (frameOffset == currentFrame) 244 | { 245 | lastFrame = currentFrame - 1; 246 | return true; 247 | } 248 | if (frameOffset == currentFrame - 1) 249 | { 250 | lastFrame = currentFrame; 251 | return true; 252 | } 253 | int64_t targetFrame = frameOffset == 0 ? 0 : frameOffset - 1; 254 | const auto ok = demuxer->seekKeyFrame(idxVideo, targetFrame); 255 | currentFrame = targetFrame; 256 | return ok; 257 | } 258 | 259 | bool Decoder::playerSeekTime(double sec) 260 | { 261 | const auto target = sec / durationV * nFramesV; 262 | const auto targetFrame = (int64_t)target; 263 | if (!opened|| targetFrame >= nFramesV) 264 | { 265 | VINFO("failed"); 266 | return false; 267 | } 268 | do 269 | { 270 | const auto df = target - currentFrame; 271 | if (targetFrame == currentFrame || (-0.5 < df && df < 0)) 272 | { 273 | // no seek, will step to next frame 274 | lastFrame = currentFrame - 1; 275 | break; 276 | } 277 | if (targetFrame == currentFrame - 1) 278 | { 279 | // wait at current frame 280 | lastFrame = currentFrame; 281 | break; 282 | } 283 | if (df <= 0) 284 | { 285 | // wait at current frame until df > 0 286 | lastFrame = currentFrame; 287 | break; 288 | } 289 | else 290 | { 291 | // note: we need to seek forward here, 292 | // but usually the game is not slower than video, 293 | // and seek forward is not a good idea when game is slower, 294 | // so we just step as usual 295 | lastFrame = currentFrame - 1; 296 | } 297 | } 298 | while (false); 299 | return true; 300 | } 301 | 302 | int64_t Decoder::tell() const 303 | { 304 | return currentFrame; 305 | } 306 | 307 | int64_t Decoder::getTotalFrames() const 308 | { 309 | return nFramesV; 310 | } 311 | 312 | double Decoder::getVideoFrameRateForPlayer() 313 | { 314 | if (!videoInfo.videoStreams.empty()) 315 | return av_q2d(getVideoFrameRate()); 316 | return Director::getInstance()->getAnimationInterval(); 317 | } 318 | 319 | Decoder::Decoder() : timeBaseV(), timeBaseA(), videoInfo() 320 | { 321 | } 322 | 323 | Decoder::~Decoder() 324 | { 325 | close(); 326 | } 327 | 328 | int64_t Decoder::getVideoFrameCount(int index) const 329 | { 330 | if (index < 0) index = idxVideoAtInfo; 331 | if (index >= videoInfo.videoStreams.size()) 332 | return 0; 333 | return videoInfo.videoStreams.at(index).numFrames; 334 | } 335 | 336 | AVRational Decoder::getVideoFrameRate(int index) const 337 | { 338 | if (index < 0) index = idxVideoAtInfo; 339 | if (index >= videoInfo.videoStreams.size()) 340 | return av_make_q(0, 0); 341 | return videoInfo.videoStreams.at(index).frameRate; 342 | } 343 | 344 | AVRational Decoder::getVideoTimeBase(int index) const 345 | { 346 | if (index < 0) index = idxVideoAtInfo; 347 | if (index >= videoInfo.videoStreams.size()) 348 | return av_make_q(0, 0); 349 | return videoInfo.videoStreams.at(index).timeBase; 350 | } 351 | 352 | int64_t Decoder::getVideoBitRate(int index) const { 353 | if (index < 0) index = idxVideoAtInfo; 354 | if(index >= videoInfo.videoStreams.size()) 355 | return 0; 356 | return videoInfo.videoStreams.at(index).bitRate; 357 | } 358 | 359 | AVPixelFormat Decoder::getVideoFormat(int index) const 360 | { 361 | if (index < 0) index = idxVideoAtInfo; 362 | if (index >= videoInfo.videoStreams.size()) 363 | return AV_PIX_FMT_NONE; 364 | return videoInfo.videoStreams.at(index).format; 365 | } 366 | 367 | std::string Decoder::getVideoFormatName(int index) const 368 | { 369 | if (index < 0) index = idxVideoAtInfo; 370 | if (index >= videoInfo.videoStreams.size()) 371 | return ""; 372 | const auto ret = videoInfo.videoStreams.at(index).formatName; 373 | return ret ? ret : ""; 374 | } 375 | 376 | Size Decoder::getVideoSize(int index) const 377 | { 378 | if (index < 0) index = idxVideoAtInfo; 379 | if (index >= videoInfo.videoStreams.size()) 380 | return { 0,0 }; 381 | auto& v = videoInfo.videoStreams.at(index); 382 | return { (float)v.width,(float)v.height }; 383 | } 384 | 385 | int64_t Decoder::getAudioFrameCount(int index) const 386 | { 387 | if (index < 0) index = idxAudioAtInfo; 388 | if (index >= videoInfo.audioStreams.size()) 389 | return 0; 390 | return videoInfo.audioStreams.at(index).numFrames; 391 | } 392 | 393 | AVRational Decoder::getAudioTimeBase(int index) const 394 | { 395 | if (index < 0) index = idxAudioAtInfo; 396 | if (index >= videoInfo.audioStreams.size()) 397 | return av_make_q(0, 0); 398 | return videoInfo.audioStreams.at(index).timeBase; 399 | } 400 | 401 | int64_t Decoder::getAudioBitRate(int index) const 402 | { 403 | if (index < 0) index = idxAudioAtInfo; 404 | if (index >= videoInfo.audioStreams.size()) 405 | return 0; 406 | return videoInfo.audioStreams.at(index).bitRate; 407 | } 408 | 409 | int Decoder::getAudioSampleRate(int index) const 410 | { 411 | if (index < 0) index = idxAudioAtInfo; 412 | if (index >= videoInfo.audioStreams.size()) 413 | return 0; 414 | return videoInfo.audioStreams.at(index).sampleRate; 415 | } 416 | 417 | int Decoder::getAudioChannelCount(int index) const 418 | { 419 | if (index < 0) index = idxAudioAtInfo; 420 | if (index >= videoInfo.audioStreams.size()) 421 | return 0; 422 | return videoInfo.audioStreams.at(index).channels; 423 | } 424 | 425 | std::string Decoder::getAudioChannelLayoutName(int index) const 426 | { 427 | if (index < 0) index = idxAudioAtInfo; 428 | if (index >= videoInfo.audioStreams.size()) 429 | return ""; 430 | auto& info = videoInfo.audioStreams.at(index); 431 | const auto ret = info.channelLayoutName; 432 | if (ret[sizeof(info.channelLayoutName) - 1] != 0) { 433 | return { ret, sizeof(info.channelLayoutName) }; 434 | } 435 | return ret; 436 | } 437 | 438 | double Decoder::getContainerDuration() const 439 | { 440 | return videoInfo.duration; 441 | } 442 | 443 | double Decoder::getContainerStartTime() const 444 | { 445 | return videoInfo.start; 446 | } 447 | 448 | int64_t Decoder::getContainerBitRate() const 449 | { 450 | return videoInfo.bitRate; 451 | } 452 | 453 | size_t Decoder::getVideoStreamCount() const 454 | { 455 | return videoInfo.videoStreams.size(); 456 | } 457 | 458 | size_t Decoder::getAudioStreamCount() const 459 | { 460 | return videoInfo.audioStreams.size(); 461 | } 462 | 463 | std::string Decoder::getVideoDecoderName() const 464 | { 465 | const auto ret = demuxer->getDecoder(idxVideo)->getCodec()->name; 466 | return ret ? ret : ""; 467 | } 468 | 469 | AVPixelFormat Decoder::getVideoDecoderHardwareFormat() const 470 | { 471 | const auto decoder = dynamic_cast(demuxer->getDecoder(idxVideo)); 472 | return decoder ? decoder->getHardwareFormat() : AV_PIX_FMT_NONE; 473 | } 474 | 475 | AVPixelFormat Decoder::getVideoDecoderSoftwareFormat() const 476 | { 477 | const auto decoder = dynamic_cast(demuxer->getDecoder(idxVideo)); 478 | return decoder ? decoder->getSoftwareFormat() : AV_PIX_FMT_NONE; 479 | } 480 | 481 | bool Decoder::isVideoDecoderHardware() const 482 | { 483 | const auto decoder = dynamic_cast(demuxer->getDecoder(idxVideo)); 484 | return decoder ? decoder->isHardware() : false; 485 | } 486 | 487 | std::string Decoder::getAudioDecoderName() const 488 | { 489 | const auto decoder = demuxer->getDecoder(idxAudio); 490 | if (!decoder) 491 | return ""; 492 | const auto ret = decoder->getCodec()->name; 493 | return ret ? ret : ""; 494 | } 495 | 496 | std::string Decoder::getPixelFormatName(AVPixelFormat format) 497 | { 498 | const auto desc = av_pix_fmt_desc_get(format); 499 | if (!desc) 500 | return ""; 501 | return desc->name; 502 | } 503 | 504 | std::vector Decoder::getAllDecoderNames() 505 | { 506 | std::vector ret; 507 | for (auto&& c : ffmpeg::Codec::getAllDecoders()) 508 | ret.emplace_back(c->name); 509 | return ret; 510 | } 511 | 512 | std::string Decoder::queryDecoderLongName(const std::string& name) 513 | { 514 | const auto codec = avcodec_find_decoder_by_name(name.c_str()); 515 | if (!codec) 516 | return ""; 517 | return codec->long_name ? codec->long_name : ""; 518 | } 519 | 520 | std::string Decoder::queryDecoderType(const std::string& name) 521 | { 522 | const auto codec = avcodec_find_decoder_by_name(name.c_str()); 523 | if (!codec) 524 | return ""; 525 | const auto ret = av_get_media_type_string(codec->type); 526 | return ret ? ret : ""; 527 | } 528 | 529 | std::string Decoder::queryDecoderID(const std::string& name) 530 | { 531 | const auto codec = avcodec_find_decoder_by_name(name.c_str()); 532 | if (!codec) 533 | return ""; 534 | return avcodec_get_name(codec->id); 535 | } 536 | 537 | bool Decoder::queryDecoderSupportsHardware(const std::string& name) 538 | { 539 | const auto codec = avcodec_find_decoder_by_name(name.c_str()); 540 | if (!codec) 541 | return false; 542 | return avcodec_get_hw_config(codec, 0); 543 | } 544 | -------------------------------------------------------------------------------- /VideoDecoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cocos2d.h" 3 | #include "VideoCommon.h" 4 | #include "VideoStream.h" 5 | #include "FFDemuxer.h" 6 | #include "FFFrameQueue.h" 7 | #include 8 | 9 | namespace video 10 | { 11 | class Decoder : public cocos2d::Ref 12 | { 13 | friend class Player; 14 | public: 15 | static Decoder* create(const std::string& path); 16 | 17 | bool open(const std::string& path); 18 | bool open(VideoStream* stream_, double loopA = 0, double loopB = -1); 19 | 20 | bool setup(); 21 | bool setup(const cocos2d::Size& target_size); 22 | 23 | bool isOpened() const; 24 | void close(); 25 | uint32_t read(uint8_t** vbuf); 26 | AVPixelFormat getReadFormat(); 27 | /** 28 | * can only seek key frame, not recommand to set a non-0 value. 29 | * will make next [read] give specified frame. 30 | */ 31 | bool seek(int64_t frameOffset); 32 | 33 | int64_t tell() const; 34 | 35 | protected: 36 | int64_t getTotalFrames() const; 37 | double getVideoFrameRateForPlayer(); 38 | 39 | public: 40 | ffmpeg::ContainerInfo getInfo() const { return videoInfo; } 41 | /** video size after convert */ 42 | cocos2d::Size getVideoTargetSize() const { return targetSize; } 43 | 44 | // video stream info 45 | 46 | int64_t getVideoFrameCount(int index = -1) const; 47 | AVRational getVideoFrameRate(int index = -1) const; 48 | AVRational getVideoTimeBase(int index = -1) const; 49 | int64_t getVideoBitRate(int index = -1) const; 50 | AVPixelFormat getVideoFormat(int index = -1) const; 51 | std::string getVideoFormatName(int index = -1) const; 52 | cocos2d::Size getVideoSize(int index = -1) const; 53 | 54 | // audio stream info 55 | 56 | int64_t getAudioFrameCount(int index = -1) const; 57 | AVRational getAudioTimeBase(int index = -1) const; 58 | int64_t getAudioBitRate(int index = -1) const; 59 | int getAudioSampleRate(int index = -1) const; 60 | int getAudioChannelCount(int index = -1) const; 61 | std::string getAudioChannelLayoutName(int index = -1) const; 62 | 63 | // container info 64 | 65 | double getContainerDuration() const; 66 | double getContainerStartTime() const; 67 | int64_t getContainerBitRate() const; 68 | size_t getVideoStreamCount() const; 69 | size_t getAudioStreamCount() const; 70 | 71 | // decoder info 72 | 73 | std::string getVideoDecoderName() const; 74 | AVPixelFormat getVideoDecoderHardwareFormat() const; 75 | AVPixelFormat getVideoDecoderSoftwareFormat() const; 76 | bool isVideoDecoderHardware() const; 77 | 78 | std::string getAudioDecoderName() const; 79 | 80 | // utils 81 | 82 | static std::string getPixelFormatName(AVPixelFormat format); 83 | static std::vector getAllDecoderNames(); 84 | static std::string queryDecoderLongName(const std::string& name); 85 | static std::string queryDecoderType(const std::string& name); 86 | static std::string queryDecoderID(const std::string& name); 87 | static bool queryDecoderSupportsHardware(const std::string& name); 88 | 89 | protected: 90 | // only used for frame control when playing 91 | bool playerSeekTime(double sec); 92 | 93 | Decoder(); 94 | ~Decoder() override; 95 | bool opened = false; 96 | VideoStream* stream = nullptr; 97 | ffmpeg::Demuxer* demuxer = nullptr; 98 | ffmpeg::AudioFrameQueue* audioQueue = nullptr; 99 | ffmpeg::VideoFrameQueue* videoQueue = nullptr; 100 | 101 | uint32_t rawWidth = 0; 102 | uint32_t rawHeight = 0; 103 | cocos2d::Size targetSize; 104 | 105 | AVRational timeBaseV; 106 | AVRational timeBaseA; 107 | 108 | AVFormatContext* pFormatCtx = nullptr; 109 | AVCodecContext* pCodecCtx = nullptr; 110 | AVCodec* pCodecV = nullptr; 111 | int idxVideo = -1; 112 | int idxAudio = -1; 113 | int idxVideoAtInfo = 0; 114 | int idxAudioAtInfo = 0; 115 | 116 | SwsContext* img_convert_ctx = nullptr; 117 | uint8_t* sws_pointers[4] = { nullptr }; 118 | int sws_linesizes[4] = { 0 }; 119 | AVPixelFormat swsFormat = AV_PIX_FMT_RGBA; 120 | 121 | ffmpeg::frame_ptr vFrame; 122 | int64_t lastFrame = -2; 123 | int64_t currentFrame = -1; 124 | 125 | std::string filePath; 126 | int64_t nFramesV = 0; 127 | double durationV = 0.0; 128 | 129 | ffmpeg::ContainerInfo videoInfo; 130 | }; 131 | } 132 | -------------------------------------------------------------------------------- /VideoPlayer.cpp: -------------------------------------------------------------------------------- 1 | #include "VideoPlayer.h" 2 | #include "renderer/backend/Device.h" 3 | 4 | using namespace video; 5 | 6 | Player* Player::create(const std::string& path) 7 | { 8 | auto ret = new (std::nothrow) Player(); 9 | if (ret&&ret->init_(path)) 10 | { 11 | ret->autorelease(); 12 | return ret; 13 | } 14 | delete ret; 15 | return nullptr; 16 | } 17 | 18 | Player::Player() 19 | { 20 | } 21 | 22 | Player::~Player() 23 | { 24 | CC_SAFE_RELEASE_NULL(decoder); 25 | } 26 | 27 | bool Player::init_(const std::string& path) 28 | { 29 | decoder = Decoder::create(path); 30 | if (!decoder) 31 | return false; 32 | decoder->retain(); 33 | if (!decoder->setup()) 34 | return false; 35 | const auto size = decoder->getVideoTargetSize(); 36 | auto texture = new (std::nothrow) cocos2d::Texture2D(); 37 | if (!texture) 38 | return false; 39 | texture->autorelease(); 40 | cocos2d::backend::TextureDescriptor desc; 41 | desc.width = size.width; 42 | desc.height = size.height; 43 | desc.textureUsage = cocos2d::TextureUsage::WRITE; 44 | desc.textureFormat = cocos2d::backend::PixelFormat::RGBA8888; 45 | #ifdef CC_VERSION 46 | texture->updateTextureDescriptor(desc); 47 | #else 48 | auto tex = cocos2d::backend::Device::getInstance()->newTexture(desc); 49 | tex->autorelease(); 50 | texture->initWithBackendTexture(tex); 51 | #endif // CC_VERSION 52 | initWithTexture(texture); 53 | setContentSize(size); 54 | _running = true; 55 | update(0); 56 | return true; 57 | } 58 | 59 | void Player::vplay() 60 | { 61 | if (mode == PlayMode::MANUAL) 62 | return; 63 | seek(0); 64 | if (!isPlaying) 65 | { 66 | if (mode == PlayMode::REALTIME) 67 | scheduleUpdate(); 68 | isPlaying = true; 69 | } 70 | autoUpdate = true; 71 | } 72 | 73 | void Player::vstop() 74 | { 75 | if (mode == PlayMode::MANUAL) 76 | return; 77 | if (isPlaying) 78 | { 79 | if (mode == PlayMode::REALTIME) 80 | unscheduleUpdate(); 81 | isPlaying = false; 82 | seek(0); 83 | } 84 | autoUpdate = false; 85 | } 86 | 87 | void Player::vpause() 88 | { 89 | if (mode == PlayMode::MANUAL) 90 | return; 91 | if (isPlaying&&autoUpdate) 92 | { 93 | if (mode == PlayMode::REALTIME) 94 | unscheduleUpdate(); 95 | isPlaying = false; 96 | } 97 | } 98 | 99 | void Player::vresume() 100 | { 101 | if (mode == PlayMode::MANUAL) 102 | return; 103 | if (!isPlaying&&autoUpdate) 104 | { 105 | if (mode == PlayMode::REALTIME) 106 | scheduleUpdate(); 107 | isPlaying = true; 108 | } 109 | } 110 | 111 | void Player::playerSeekTime(double sec) 112 | { 113 | if (decoder->playerSeekTime(sec)) 114 | { 115 | currentTime = sec; 116 | } 117 | } 118 | 119 | void Player::seek(uint32_t frame) 120 | { 121 | if (decoder->seek(frame)) 122 | { 123 | currentTime = frame / decoder->getVideoFrameRateForPlayer(); 124 | } 125 | } 126 | 127 | void Player::update(float dt) 128 | { 129 | cocos2d::Sprite::update(dt); 130 | if (dt >= 0) 131 | { 132 | playerSeekTime(currentTime); 133 | currentTime += dt; 134 | } 135 | else 136 | { 137 | currentTime += 1.0 / decoder->getVideoFrameRateForPlayer(); 138 | } 139 | auto ret = decoder->read(&vbuf); 140 | texureDirty = ret != 0 && vbuf; 141 | if (decoder->tell() == decoder->getTotalFrames() - 1/* || !vbuf*/) 142 | { 143 | vstop(); 144 | if (videoEndCallback) 145 | videoEndCallback(); 146 | if (autoRemove) 147 | { 148 | // stop texture update 149 | vbuf = nullptr; 150 | // avoid memory conflict 151 | scheduleOnce([this](float dt_) 152 | { 153 | removeFromParentAndCleanup(true); 154 | }, 0, "remove"); 155 | } 156 | } 157 | } 158 | 159 | void Player::setPlayMode(PlayMode m) 160 | { 161 | if (m != PlayMode::REALTIME) 162 | { 163 | unscheduleUpdate(); 164 | } 165 | mode = m; 166 | } 167 | 168 | void Player::draw(cocos2d::Renderer* renderer, const cocos2d::Mat4 &transform, uint32_t flags) 169 | { 170 | if (!_texture) 171 | return; 172 | if (isPlaying) 173 | { 174 | if (mode == PlayMode::STEP) 175 | { 176 | update(step); 177 | } 178 | else if (mode == PlayMode::FRAME) 179 | { 180 | update(-1); 181 | } 182 | if (texureDirty && vbuf) 183 | { 184 | #ifdef CC_VERSION 185 | const int length = _contentSize.width * _contentSize.height; 186 | size_t dataSize = 0; 187 | cocos2d::PixelFormat format; 188 | if (decoder->getReadFormat() == AV_PIX_FMT_RGBA) 189 | { 190 | dataSize = length * 4; 191 | format = cocos2d::PixelFormat::RGBA8; 192 | } 193 | else 194 | { 195 | dataSize = length * 3; 196 | format = cocos2d::PixelFormat::RGB8; 197 | } 198 | _texture->updateWithData( 199 | vbuf, dataSize, 200 | format, 201 | cocos2d::PixelFormat::RGBA8888, 202 | _texture->getPixelsWide(), 203 | _texture->getPixelsHigh(), 204 | false); 205 | #else 206 | _texture->updateWithData(vbuf, 0, 0, 207 | _texture->getPixelsWide(), 208 | _texture->getPixelsHigh()); 209 | #endif // CC_VERSION 210 | } 211 | } 212 | 213 | cocos2d::Sprite::draw(renderer, transform, flags); 214 | } 215 | 216 | void Player::setVideoEndCallback(const std::function& func) 217 | { 218 | videoEndCallback = func; 219 | } 220 | 221 | void Player::saveCurrentFrame(const std::string& path) 222 | { 223 | if (!vbuf) 224 | return; 225 | auto im = new cocos2d::Image(); 226 | const int length = _contentSize.width * _contentSize.height; 227 | const size_t dataSize = length * 4; 228 | std::vector buffer; 229 | uint8_t* buf; 230 | if (decoder->getReadFormat() == AV_PIX_FMT_RGBA) 231 | { 232 | buf = vbuf; 233 | } 234 | else 235 | { 236 | buffer.resize(dataSize); 237 | buf = buffer.data(); 238 | for (int i = 0; i < length; ++i) 239 | { 240 | buf[i * 4] = vbuf[i * 3]; 241 | buf[i * 4 + 1] = vbuf[i * 3 + 1]; 242 | buf[i * 4 + 2] = vbuf[i * 3 + 2]; 243 | buf[i * 4 + 3] = 255; 244 | } 245 | } 246 | im->initWithRawData(buf, dataSize, 247 | _contentSize.width, _contentSize.height, 32); 248 | im->saveToFile(path); 249 | delete im; 250 | } 251 | -------------------------------------------------------------------------------- /VideoPlayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cocos2d.h" 3 | #include "VideoDecoder.h" 4 | #include 5 | 6 | namespace video 7 | { 8 | class Player : public cocos2d::Sprite 9 | { 10 | public: 11 | enum class PlayMode 12 | { 13 | /** step a const time per frame */ 14 | STEP, 15 | /** realtime time -> video time, not recommended */ 16 | REALTIME, 17 | /** game frame -> video frame */ 18 | FRAME, 19 | /** invoke update manually */ 20 | MANUAL, 21 | }; 22 | static Player* create(const std::string& path); 23 | protected: 24 | bool init_(const std::string& path); 25 | public: 26 | void vplay(); 27 | void vstop(); 28 | void vpause(); 29 | void vresume(); 30 | /** can only seek key frame, not recommended to set a non-0 value */ 31 | void seek(uint32_t frame); 32 | /** step dt in decoder and get data, will step 1 frame if dt<0 */ 33 | void update(float dt) override; 34 | 35 | /** see PlayMode */ 36 | void setPlayMode(PlayMode m); 37 | /** used for PlayMode::STEP mode */ 38 | void setStep(double v) { step = v; } 39 | /** auto invoke removeFromParentAndCleanup when finished */ 40 | void setAutoRemove(bool b) { autoRemove = b; } 41 | /** set callback when finished */ 42 | void setVideoEndCallback(const std::function& func); 43 | /** save current frame to file */ 44 | void saveCurrentFrame(const std::string& path); 45 | 46 | Decoder* getDecoder() const { return decoder; } 47 | 48 | protected: 49 | void draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags) override; 50 | void playerSeekTime(double sec); 51 | Decoder* decoder = nullptr; 52 | uint8_t* vbuf = nullptr; 53 | 54 | double currentTime = 0.0; 55 | double step = 1.0 / 60; 56 | bool autoUpdate = false; 57 | bool autoRemove = false; 58 | bool isPlaying = false; 59 | bool texureDirty = false; 60 | PlayMode mode = PlayMode::STEP; 61 | 62 | std::function videoEndCallback; 63 | 64 | Player(); 65 | ~Player() override; 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /VideoStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "base/CCRef.h" 3 | #include 4 | 5 | namespace video 6 | { 7 | class VideoStream : public cocos2d::Ref 8 | { 9 | public: 10 | enum class SeekOrigin 11 | { 12 | /** Seek from the beginning. */ 13 | BEGINNING = 0, 14 | /** Seek from current position. */ 15 | CURRENT = 1, 16 | /** Seek from the end. */ 17 | END = 2 18 | }; 19 | 20 | virtual uint64_t size() = 0; 21 | virtual uint64_t tell() = 0; 22 | virtual bool seek(SeekOrigin origin, int64_t offset) = 0; 23 | virtual bool read(uint8_t* dst, uint64_t length, uint64_t* bytesRead = nullptr) = 0; 24 | 25 | virtual void lock() = 0; 26 | virtual void unlock() = 0; 27 | 28 | virtual ~VideoStream() = default; 29 | }; 30 | 31 | template 32 | class VideoStreamAdapter { }; 33 | 34 | template<> 35 | class VideoStreamAdapter : public VideoStream 36 | { 37 | uint64_t _pos = 0; 38 | uint8_t* _buffer; 39 | uint64_t _size; 40 | std::mutex _mut; 41 | public: 42 | explicit VideoStreamAdapter(uint8_t* buffer, uint64_t size) : _buffer(buffer), _size(size) 43 | { 44 | autorelease(); 45 | } 46 | 47 | uint64_t size() override { return _size; } 48 | uint64_t tell() override { return _pos; } 49 | bool seek(SeekOrigin origin, int64_t offset) override 50 | { 51 | switch (origin) { 52 | case SeekOrigin::BEGINNING: _pos = 0; break; 53 | case SeekOrigin::CURRENT: break; 54 | case SeekOrigin::END: _pos = _size; break; 55 | default: return false; 56 | } 57 | if (offset < 0 && uint64_t(-offset) > _pos) 58 | { 59 | _pos = 0; 60 | return false; 61 | } 62 | if (offset > 0 && offset + _pos >= _size) 63 | { 64 | _pos = _size; 65 | return false; 66 | } 67 | _pos += offset; 68 | return true; 69 | } 70 | bool read(uint8_t* dst, uint64_t length, uint64_t* bytesRead = nullptr) override 71 | { 72 | if (bytesRead) *bytesRead = 0; 73 | if (length == 0) return true; 74 | if (!dst) return false; 75 | 76 | const uint64_t rest_size = _size - _pos; 77 | if (rest_size == 0) return false; 78 | 79 | const size_t real_read = std::min(length, rest_size); 80 | memcpy(dst, _buffer + _pos, real_read); 81 | _pos += real_read; 82 | if (bytesRead) *bytesRead = real_read; 83 | 84 | return rest_size >= length; 85 | } 86 | void lock() override { _mut.lock(); } 87 | void unlock() override { _mut.unlock(); } 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /lua_video_auto.cpp: -------------------------------------------------------------------------------- 1 | #include "lua_video_auto.hpp" 2 | #include "VideoPlayer.h" 3 | #include "scripting/lua-bindings/manual/tolua_fix.h" 4 | #include "scripting/lua-bindings/manual/LuaBasicConversions.h" 5 | 6 | #ifndef LUA_CHECK_COBJ_TYPE 7 | #ifdef LUA_DEBUG 8 | #define LUA_CHECK_COBJ_TYPE(L, TYPE, NAME) if(!tolua_isusertype((L), 1, (TYPE), 0, nullptr)) { return luaL_error((L), "invalid 'cobj' in '%s': '%s', expects '%s'", NAME, tolua_typename((L), 1), (TYPE)); } 9 | #else 10 | #define LUA_CHECK_COBJ_TYPE(L, TYPE, NAME) (void)(TYPE); 11 | #endif 12 | #endif 13 | #ifndef LUA_CHECK_COBJ 14 | #ifdef LUA_DEBUG 15 | #define LUA_CHECK_COBJ(L, COBJ, NAME) if(!(COBJ)) { return luaL_error((L), "invalid 'cobj' in '%s'", NAME); } 16 | #else 17 | #define LUA_CHECK_COBJ(L, COBJ, NAME) 18 | #endif 19 | #endif 20 | #ifndef LUA_CHECK_PARAMETER 21 | #define LUA_CHECK_PARAMETER(L, OK, NAME) if(!(OK)) { return luaL_error((L), "invalid arguments in '%s'", NAME); } 22 | #endif 23 | #ifndef LUA_PARAMETER_ERROR 24 | #define LUA_PARAMETER_ERROR(L, NAME, ARGC, EXPECT) return luaL_error((L), "wrong number of arguments in '%s': %d, expects %s", NAME, (ARGC), EXPECT); 25 | #endif 26 | 27 | void AVRational_to_luaval(lua_State* L, const AVRational& value) 28 | { 29 | lua_createtable(L, 0, 2); 30 | lua_pushinteger(L, value.num); 31 | lua_setfield(L, -2, "num"); 32 | lua_pushinteger(L, value.den); 33 | lua_setfield(L, -2, "den"); 34 | } 35 | 36 | int lua_cc_video_Decoder_getAllDecoderNames(lua_State* tolua_S) 37 | { 38 | bool ok = true; 39 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 40 | constexpr auto LUA_FNAME = "video.Decoder:getAllDecoderNames"; 41 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 42 | const int argc = lua_gettop(tolua_S) - 1; 43 | if (argc == 0) { 44 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 45 | auto ret = video::Decoder::getAllDecoderNames(); 46 | ccvector_std_string_to_luaval(tolua_S, ret); 47 | return 1; 48 | } 49 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 50 | } 51 | int lua_cc_video_Decoder_getAudioBitRate(lua_State* tolua_S) 52 | { 53 | bool ok = true; 54 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 55 | constexpr auto LUA_FNAME = "video.Decoder:getAudioBitRate"; 56 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 57 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 58 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 59 | const int argc = lua_gettop(tolua_S) - 1; 60 | if (argc == 0) { 61 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 62 | auto ret = cobj->getAudioBitRate(); 63 | tolua_pushnumber(tolua_S, (lua_Number)ret); 64 | return 1; 65 | } 66 | if (argc == 1) { 67 | int arg0; 68 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 69 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 70 | auto ret = cobj->getAudioBitRate(arg0); 71 | tolua_pushnumber(tolua_S, (lua_Number)ret); 72 | return 1; 73 | } 74 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 75 | } 76 | int lua_cc_video_Decoder_getAudioChannelCount(lua_State* tolua_S) 77 | { 78 | bool ok = true; 79 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 80 | constexpr auto LUA_FNAME = "video.Decoder:getAudioChannelCount"; 81 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 82 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 83 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 84 | const int argc = lua_gettop(tolua_S) - 1; 85 | if (argc == 0) { 86 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 87 | auto ret = cobj->getAudioChannelCount(); 88 | tolua_pushnumber(tolua_S, (lua_Number)ret); 89 | return 1; 90 | } 91 | if (argc == 1) { 92 | int arg0; 93 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 94 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 95 | auto ret = cobj->getAudioChannelCount(arg0); 96 | tolua_pushnumber(tolua_S, (lua_Number)ret); 97 | return 1; 98 | } 99 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 100 | } 101 | int lua_cc_video_Decoder_getAudioChannelLayoutName(lua_State* tolua_S) 102 | { 103 | bool ok = true; 104 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 105 | constexpr auto LUA_FNAME = "video.Decoder:getAudioChannelLayoutName"; 106 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 107 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 108 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 109 | const int argc = lua_gettop(tolua_S) - 1; 110 | if (argc == 0) { 111 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 112 | auto ret = cobj->getAudioChannelLayoutName(); 113 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 114 | return 1; 115 | } 116 | if (argc == 1) { 117 | int arg0; 118 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 119 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 120 | auto ret = cobj->getAudioChannelLayoutName(arg0); 121 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 122 | return 1; 123 | } 124 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 125 | } 126 | int lua_cc_video_Decoder_getAudioDecoderName(lua_State* tolua_S) 127 | { 128 | bool ok = true; 129 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 130 | constexpr auto LUA_FNAME = "video.Decoder:getAudioDecoderName"; 131 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 132 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 133 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 134 | const int argc = lua_gettop(tolua_S) - 1; 135 | if (argc == 0) { 136 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 137 | auto ret = cobj->getAudioDecoderName(); 138 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 139 | return 1; 140 | } 141 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 142 | } 143 | int lua_cc_video_Decoder_getAudioFrameCount(lua_State* tolua_S) 144 | { 145 | bool ok = true; 146 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 147 | constexpr auto LUA_FNAME = "video.Decoder:getAudioFrameCount"; 148 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 149 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 150 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 151 | const int argc = lua_gettop(tolua_S) - 1; 152 | if (argc == 0) { 153 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 154 | auto ret = cobj->getAudioFrameCount(); 155 | tolua_pushnumber(tolua_S, (lua_Number)ret); 156 | return 1; 157 | } 158 | if (argc == 1) { 159 | int arg0; 160 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 161 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 162 | auto ret = cobj->getAudioFrameCount(arg0); 163 | tolua_pushnumber(tolua_S, (lua_Number)ret); 164 | return 1; 165 | } 166 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 167 | } 168 | int lua_cc_video_Decoder_getAudioSampleRate(lua_State* tolua_S) 169 | { 170 | bool ok = true; 171 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 172 | constexpr auto LUA_FNAME = "video.Decoder:getAudioSampleRate"; 173 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 174 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 175 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 176 | const int argc = lua_gettop(tolua_S) - 1; 177 | if (argc == 0) { 178 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 179 | auto ret = cobj->getAudioSampleRate(); 180 | tolua_pushnumber(tolua_S, (lua_Number)ret); 181 | return 1; 182 | } 183 | if (argc == 1) { 184 | int arg0; 185 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 186 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 187 | auto ret = cobj->getAudioSampleRate(arg0); 188 | tolua_pushnumber(tolua_S, (lua_Number)ret); 189 | return 1; 190 | } 191 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 192 | } 193 | int lua_cc_video_Decoder_getAudioStreamCount(lua_State* tolua_S) 194 | { 195 | bool ok = true; 196 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 197 | constexpr auto LUA_FNAME = "video.Decoder:getAudioStreamCount"; 198 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 199 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 200 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 201 | const int argc = lua_gettop(tolua_S) - 1; 202 | if (argc == 0) { 203 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 204 | auto ret = cobj->getAudioStreamCount(); 205 | tolua_pushnumber(tolua_S, (lua_Number)ret); 206 | return 1; 207 | } 208 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 209 | } 210 | int lua_cc_video_Decoder_getAudioTimeBase(lua_State* tolua_S) 211 | { 212 | bool ok = true; 213 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 214 | constexpr auto LUA_FNAME = "video.Decoder:getAudioTimeBase"; 215 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 216 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 217 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 218 | const int argc = lua_gettop(tolua_S) - 1; 219 | if (argc == 0) { 220 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 221 | auto ret = cobj->getAudioTimeBase(); 222 | AVRational_to_luaval(tolua_S, ret); 223 | return 1; 224 | } 225 | if (argc == 1) { 226 | int arg0; 227 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 228 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 229 | auto ret = cobj->getAudioTimeBase(arg0); 230 | AVRational_to_luaval(tolua_S, ret); 231 | return 1; 232 | } 233 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 234 | } 235 | int lua_cc_video_Decoder_getContainerBitRate(lua_State* tolua_S) 236 | { 237 | bool ok = true; 238 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 239 | constexpr auto LUA_FNAME = "video.Decoder:getContainerBitRate"; 240 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 241 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 242 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 243 | const int argc = lua_gettop(tolua_S) - 1; 244 | if (argc == 0) { 245 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 246 | auto ret = cobj->getContainerBitRate(); 247 | tolua_pushnumber(tolua_S, (lua_Number)ret); 248 | return 1; 249 | } 250 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 251 | } 252 | int lua_cc_video_Decoder_getContainerDuration(lua_State* tolua_S) 253 | { 254 | bool ok = true; 255 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 256 | constexpr auto LUA_FNAME = "video.Decoder:getContainerDuration"; 257 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 258 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 259 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 260 | const int argc = lua_gettop(tolua_S) - 1; 261 | if (argc == 0) { 262 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 263 | auto ret = cobj->getContainerDuration(); 264 | tolua_pushnumber(tolua_S, (lua_Number)ret); 265 | return 1; 266 | } 267 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 268 | } 269 | int lua_cc_video_Decoder_getContainerStartTime(lua_State* tolua_S) 270 | { 271 | bool ok = true; 272 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 273 | constexpr auto LUA_FNAME = "video.Decoder:getContainerStartTime"; 274 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 275 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 276 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 277 | const int argc = lua_gettop(tolua_S) - 1; 278 | if (argc == 0) { 279 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 280 | auto ret = cobj->getContainerStartTime(); 281 | tolua_pushnumber(tolua_S, (lua_Number)ret); 282 | return 1; 283 | } 284 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 285 | } 286 | int lua_cc_video_Decoder_getPixelFormatName(lua_State* tolua_S) 287 | { 288 | bool ok = true; 289 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 290 | constexpr auto LUA_FNAME = "video.Decoder:getPixelFormatName"; 291 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 292 | const int argc = lua_gettop(tolua_S) - 1; 293 | if (argc == 1) { 294 | AVPixelFormat arg0; 295 | int arg0_tmp; ok &= luaval_to_int32(tolua_S, 2, &arg0_tmp, LUA_FNAME); arg0 = (AVPixelFormat)arg0_tmp; 296 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 297 | auto ret = video::Decoder::getPixelFormatName(arg0); 298 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 299 | return 1; 300 | } 301 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 302 | } 303 | int lua_cc_video_Decoder_getVideoBitRate(lua_State* tolua_S) 304 | { 305 | bool ok = true; 306 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 307 | constexpr auto LUA_FNAME = "video.Decoder:getVideoBitRate"; 308 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 309 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 310 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 311 | const int argc = lua_gettop(tolua_S) - 1; 312 | if (argc == 0) { 313 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 314 | auto ret = cobj->getVideoBitRate(); 315 | tolua_pushnumber(tolua_S, (lua_Number)ret); 316 | return 1; 317 | } 318 | if (argc == 1) { 319 | int arg0; 320 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 321 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 322 | auto ret = cobj->getVideoBitRate(arg0); 323 | tolua_pushnumber(tolua_S, (lua_Number)ret); 324 | return 1; 325 | } 326 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 327 | } 328 | int lua_cc_video_Decoder_getVideoDecoderHardwareFormat(lua_State* tolua_S) 329 | { 330 | bool ok = true; 331 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 332 | constexpr auto LUA_FNAME = "video.Decoder:getVideoDecoderHardwareFormat"; 333 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 334 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 335 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 336 | const int argc = lua_gettop(tolua_S) - 1; 337 | if (argc == 0) { 338 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 339 | auto ret = cobj->getVideoDecoderHardwareFormat(); 340 | tolua_pushnumber(tolua_S, (lua_Number)ret); 341 | return 1; 342 | } 343 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 344 | } 345 | int lua_cc_video_Decoder_getVideoDecoderName(lua_State* tolua_S) 346 | { 347 | bool ok = true; 348 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 349 | constexpr auto LUA_FNAME = "video.Decoder:getVideoDecoderName"; 350 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 351 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 352 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 353 | const int argc = lua_gettop(tolua_S) - 1; 354 | if (argc == 0) { 355 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 356 | auto ret = cobj->getVideoDecoderName(); 357 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 358 | return 1; 359 | } 360 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 361 | } 362 | int lua_cc_video_Decoder_getVideoDecoderSoftwareFormat(lua_State* tolua_S) 363 | { 364 | bool ok = true; 365 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 366 | constexpr auto LUA_FNAME = "video.Decoder:getVideoDecoderSoftwareFormat"; 367 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 368 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 369 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 370 | const int argc = lua_gettop(tolua_S) - 1; 371 | if (argc == 0) { 372 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 373 | auto ret = cobj->getVideoDecoderSoftwareFormat(); 374 | tolua_pushnumber(tolua_S, (lua_Number)ret); 375 | return 1; 376 | } 377 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 378 | } 379 | int lua_cc_video_Decoder_getVideoFormat(lua_State* tolua_S) 380 | { 381 | bool ok = true; 382 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 383 | constexpr auto LUA_FNAME = "video.Decoder:getVideoFormat"; 384 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 385 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 386 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 387 | const int argc = lua_gettop(tolua_S) - 1; 388 | if (argc == 0) { 389 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 390 | auto ret = cobj->getVideoFormat(); 391 | tolua_pushnumber(tolua_S, (lua_Number)ret); 392 | return 1; 393 | } 394 | if (argc == 1) { 395 | int arg0; 396 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 397 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 398 | auto ret = cobj->getVideoFormat(arg0); 399 | tolua_pushnumber(tolua_S, (lua_Number)ret); 400 | return 1; 401 | } 402 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 403 | } 404 | int lua_cc_video_Decoder_getVideoFormatName(lua_State* tolua_S) 405 | { 406 | bool ok = true; 407 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 408 | constexpr auto LUA_FNAME = "video.Decoder:getVideoFormatName"; 409 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 410 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 411 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 412 | const int argc = lua_gettop(tolua_S) - 1; 413 | if (argc == 0) { 414 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 415 | auto ret = cobj->getVideoFormatName(); 416 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 417 | return 1; 418 | } 419 | if (argc == 1) { 420 | int arg0; 421 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 422 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 423 | auto ret = cobj->getVideoFormatName(arg0); 424 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 425 | return 1; 426 | } 427 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 428 | } 429 | int lua_cc_video_Decoder_getVideoFrameCount(lua_State* tolua_S) 430 | { 431 | bool ok = true; 432 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 433 | constexpr auto LUA_FNAME = "video.Decoder:getVideoFrameCount"; 434 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 435 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 436 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 437 | const int argc = lua_gettop(tolua_S) - 1; 438 | if (argc == 0) { 439 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 440 | auto ret = cobj->getVideoFrameCount(); 441 | tolua_pushnumber(tolua_S, (lua_Number)ret); 442 | return 1; 443 | } 444 | if (argc == 1) { 445 | int arg0; 446 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 447 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 448 | auto ret = cobj->getVideoFrameCount(arg0); 449 | tolua_pushnumber(tolua_S, (lua_Number)ret); 450 | return 1; 451 | } 452 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 453 | } 454 | int lua_cc_video_Decoder_getVideoFrameRate(lua_State* tolua_S) 455 | { 456 | bool ok = true; 457 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 458 | constexpr auto LUA_FNAME = "video.Decoder:getVideoFrameRate"; 459 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 460 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 461 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 462 | const int argc = lua_gettop(tolua_S) - 1; 463 | if (argc == 0) { 464 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 465 | auto ret = cobj->getVideoFrameRate(); 466 | AVRational_to_luaval(tolua_S, ret); 467 | return 1; 468 | } 469 | if (argc == 1) { 470 | int arg0; 471 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 472 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 473 | auto ret = cobj->getVideoFrameRate(arg0); 474 | AVRational_to_luaval(tolua_S, ret); 475 | return 1; 476 | } 477 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 478 | } 479 | int lua_cc_video_Decoder_getVideoSize(lua_State* tolua_S) 480 | { 481 | bool ok = true; 482 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 483 | constexpr auto LUA_FNAME = "video.Decoder:getVideoSize"; 484 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 485 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 486 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 487 | const int argc = lua_gettop(tolua_S) - 1; 488 | if (argc == 0) { 489 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 490 | auto ret = cobj->getVideoSize(); 491 | size_to_luaval(tolua_S, ret); 492 | return 1; 493 | } 494 | if (argc == 1) { 495 | int arg0; 496 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 497 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 498 | auto ret = cobj->getVideoSize(arg0); 499 | size_to_luaval(tolua_S, ret); 500 | return 1; 501 | } 502 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 503 | } 504 | int lua_cc_video_Decoder_getVideoStreamCount(lua_State* tolua_S) 505 | { 506 | bool ok = true; 507 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 508 | constexpr auto LUA_FNAME = "video.Decoder:getVideoStreamCount"; 509 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 510 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 511 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 512 | const int argc = lua_gettop(tolua_S) - 1; 513 | if (argc == 0) { 514 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 515 | auto ret = cobj->getVideoStreamCount(); 516 | tolua_pushnumber(tolua_S, (lua_Number)ret); 517 | return 1; 518 | } 519 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 520 | } 521 | int lua_cc_video_Decoder_getVideoTargetSize(lua_State* tolua_S) 522 | { 523 | bool ok = true; 524 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 525 | constexpr auto LUA_FNAME = "video.Decoder:getVideoTargetSize"; 526 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 527 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 528 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 529 | const int argc = lua_gettop(tolua_S) - 1; 530 | if (argc == 0) { 531 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 532 | auto ret = cobj->getVideoTargetSize(); 533 | size_to_luaval(tolua_S, ret); 534 | return 1; 535 | } 536 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 537 | } 538 | int lua_cc_video_Decoder_getVideoTimeBase(lua_State* tolua_S) 539 | { 540 | bool ok = true; 541 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 542 | constexpr auto LUA_FNAME = "video.Decoder:getVideoTimeBase"; 543 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 544 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 545 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 546 | const int argc = lua_gettop(tolua_S) - 1; 547 | if (argc == 0) { 548 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 549 | auto ret = cobj->getVideoTimeBase(); 550 | AVRational_to_luaval(tolua_S, ret); 551 | return 1; 552 | } 553 | if (argc == 1) { 554 | int arg0; 555 | ok &= luaval_to_int32(tolua_S, 2, &arg0, LUA_FNAME); 556 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 557 | auto ret = cobj->getVideoTimeBase(arg0); 558 | AVRational_to_luaval(tolua_S, ret); 559 | return 1; 560 | } 561 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0 to 1"); 562 | } 563 | int lua_cc_video_Decoder_isVideoDecoderHardware(lua_State* tolua_S) 564 | { 565 | bool ok = true; 566 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 567 | constexpr auto LUA_FNAME = "video.Decoder:isVideoDecoderHardware"; 568 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 569 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 570 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 571 | const int argc = lua_gettop(tolua_S) - 1; 572 | if (argc == 0) { 573 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 574 | auto ret = cobj->isVideoDecoderHardware(); 575 | tolua_pushboolean(tolua_S, (bool)ret); 576 | return 1; 577 | } 578 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 579 | } 580 | int lua_cc_video_Decoder_queryDecoderID(lua_State* tolua_S) 581 | { 582 | bool ok = true; 583 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 584 | constexpr auto LUA_FNAME = "video.Decoder:queryDecoderID"; 585 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 586 | const int argc = lua_gettop(tolua_S) - 1; 587 | if (argc == 1) { 588 | std::string arg0; 589 | ok &= luaval_to_std_string(tolua_S, 2, &arg0, LUA_FNAME); 590 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 591 | auto ret = video::Decoder::queryDecoderID(arg0); 592 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 593 | return 1; 594 | } 595 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 596 | } 597 | int lua_cc_video_Decoder_queryDecoderLongName(lua_State* tolua_S) 598 | { 599 | bool ok = true; 600 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 601 | constexpr auto LUA_FNAME = "video.Decoder:queryDecoderLongName"; 602 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 603 | const int argc = lua_gettop(tolua_S) - 1; 604 | if (argc == 1) { 605 | std::string arg0; 606 | ok &= luaval_to_std_string(tolua_S, 2, &arg0, LUA_FNAME); 607 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 608 | auto ret = video::Decoder::queryDecoderLongName(arg0); 609 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 610 | return 1; 611 | } 612 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 613 | } 614 | int lua_cc_video_Decoder_queryDecoderSupportsHardware(lua_State* tolua_S) 615 | { 616 | bool ok = true; 617 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 618 | constexpr auto LUA_FNAME = "video.Decoder:queryDecoderSupportsHardware"; 619 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 620 | const int argc = lua_gettop(tolua_S) - 1; 621 | if (argc == 1) { 622 | std::string arg0; 623 | ok &= luaval_to_std_string(tolua_S, 2, &arg0, LUA_FNAME); 624 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 625 | auto ret = video::Decoder::queryDecoderSupportsHardware(arg0); 626 | tolua_pushboolean(tolua_S, (bool)ret); 627 | return 1; 628 | } 629 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 630 | } 631 | int lua_cc_video_Decoder_queryDecoderType(lua_State* tolua_S) 632 | { 633 | bool ok = true; 634 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 635 | constexpr auto LUA_FNAME = "video.Decoder:queryDecoderType"; 636 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 637 | const int argc = lua_gettop(tolua_S) - 1; 638 | if (argc == 1) { 639 | std::string arg0; 640 | ok &= luaval_to_std_string(tolua_S, 2, &arg0, LUA_FNAME); 641 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 642 | auto ret = video::Decoder::queryDecoderType(arg0); 643 | lua_pushlstring(tolua_S, ret.c_str(), ret.length()); 644 | return 1; 645 | } 646 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 647 | } 648 | int lua_cc_video_Decoder_tell(lua_State* tolua_S) 649 | { 650 | bool ok = true; 651 | constexpr auto LUA_OBJ_TYPE = "video.Decoder"; 652 | constexpr auto LUA_FNAME = "video.Decoder:tell"; 653 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 654 | auto cobj = (video::Decoder*)tolua_tousertype(tolua_S, 1, nullptr); 655 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 656 | const int argc = lua_gettop(tolua_S) - 1; 657 | if (argc == 0) { 658 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 659 | auto ret = cobj->tell(); 660 | tolua_pushnumber(tolua_S, (lua_Number)ret); 661 | return 1; 662 | } 663 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 664 | } 665 | static int lua_cc_video_Decoder_finalize(lua_State* tolua_S) 666 | { 667 | return 0; 668 | } 669 | 670 | int lua_register_cc_video_Decoder(lua_State* tolua_S) 671 | { 672 | tolua_usertype(tolua_S, "video.Decoder"); 673 | tolua_cclass(tolua_S, "Decoder", "video.Decoder", "cc.Ref", nullptr); 674 | 675 | tolua_beginmodule(tolua_S, "Decoder"); 676 | tolua_function(tolua_S, "getAudioBitRate", lua_cc_video_Decoder_getAudioBitRate); 677 | tolua_function(tolua_S, "getAudioChannelCount", lua_cc_video_Decoder_getAudioChannelCount); 678 | tolua_function(tolua_S, "getAudioChannelLayoutName", lua_cc_video_Decoder_getAudioChannelLayoutName); 679 | tolua_function(tolua_S, "getAudioDecoderName", lua_cc_video_Decoder_getAudioDecoderName); 680 | tolua_function(tolua_S, "getAudioFrameCount", lua_cc_video_Decoder_getAudioFrameCount); 681 | tolua_function(tolua_S, "getAudioSampleRate", lua_cc_video_Decoder_getAudioSampleRate); 682 | tolua_function(tolua_S, "getAudioStreamCount", lua_cc_video_Decoder_getAudioStreamCount); 683 | tolua_function(tolua_S, "getAudioTimeBase", lua_cc_video_Decoder_getAudioTimeBase); 684 | tolua_function(tolua_S, "getContainerBitRate", lua_cc_video_Decoder_getContainerBitRate); 685 | tolua_function(tolua_S, "getContainerDuration", lua_cc_video_Decoder_getContainerDuration); 686 | tolua_function(tolua_S, "getContainerStartTime", lua_cc_video_Decoder_getContainerStartTime); 687 | tolua_function(tolua_S, "getVideoBitRate", lua_cc_video_Decoder_getVideoBitRate); 688 | tolua_function(tolua_S, "getVideoDecoderHardwareFormat", lua_cc_video_Decoder_getVideoDecoderHardwareFormat); 689 | tolua_function(tolua_S, "getVideoDecoderName", lua_cc_video_Decoder_getVideoDecoderName); 690 | tolua_function(tolua_S, "getVideoDecoderSoftwareFormat", lua_cc_video_Decoder_getVideoDecoderSoftwareFormat); 691 | tolua_function(tolua_S, "getVideoFormat", lua_cc_video_Decoder_getVideoFormat); 692 | tolua_function(tolua_S, "getVideoFormatName", lua_cc_video_Decoder_getVideoFormatName); 693 | tolua_function(tolua_S, "getVideoFrameCount", lua_cc_video_Decoder_getVideoFrameCount); 694 | tolua_function(tolua_S, "getVideoFrameRate", lua_cc_video_Decoder_getVideoFrameRate); 695 | tolua_function(tolua_S, "getVideoSize", lua_cc_video_Decoder_getVideoSize); 696 | tolua_function(tolua_S, "getVideoStreamCount", lua_cc_video_Decoder_getVideoStreamCount); 697 | tolua_function(tolua_S, "getVideoTargetSize", lua_cc_video_Decoder_getVideoTargetSize); 698 | tolua_function(tolua_S, "getVideoTimeBase", lua_cc_video_Decoder_getVideoTimeBase); 699 | tolua_function(tolua_S, "isVideoDecoderHardware", lua_cc_video_Decoder_isVideoDecoderHardware); 700 | tolua_function(tolua_S, "tell", lua_cc_video_Decoder_tell); 701 | tolua_function(tolua_S, "getAllDecoderNames", lua_cc_video_Decoder_getAllDecoderNames); 702 | tolua_function(tolua_S, "getPixelFormatName", lua_cc_video_Decoder_getPixelFormatName); 703 | tolua_function(tolua_S, "queryDecoderID", lua_cc_video_Decoder_queryDecoderID); 704 | tolua_function(tolua_S, "queryDecoderLongName", lua_cc_video_Decoder_queryDecoderLongName); 705 | tolua_function(tolua_S, "queryDecoderSupportsHardware", lua_cc_video_Decoder_queryDecoderSupportsHardware); 706 | tolua_function(tolua_S, "queryDecoderType", lua_cc_video_Decoder_queryDecoderType); 707 | tolua_endmodule(tolua_S); 708 | const auto typeName = reinterpret_cast(typeid(video::Decoder).name()); 709 | g_luaType[typeName] = "video.Decoder"; 710 | g_typeCast["Decoder"] = "video.Decoder"; 711 | return 1; 712 | } 713 | 714 | int lua_cc_video_Player_create(lua_State* tolua_S) 715 | { 716 | bool ok = true; 717 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 718 | constexpr auto LUA_FNAME = "video.Player:create"; 719 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 720 | const int argc = lua_gettop(tolua_S) - 1; 721 | if (argc == 1) { 722 | std::string arg0; 723 | ok &= luaval_to_std_string(tolua_S, 2, &arg0, LUA_FNAME); 724 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 725 | auto ret = video::Player::create(arg0); 726 | object_to_luaval(tolua_S, "video.Player", (video::Player*)ret); 727 | return 1; 728 | } 729 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 730 | } 731 | int lua_cc_video_Player_getDecoder(lua_State* tolua_S) 732 | { 733 | bool ok = true; 734 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 735 | constexpr auto LUA_FNAME = "video.Player:getDecoder"; 736 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 737 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 738 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 739 | const int argc = lua_gettop(tolua_S) - 1; 740 | if (argc == 0) { 741 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 742 | auto ret = cobj->getDecoder(); 743 | object_to_luaval(tolua_S, "video.Decoder", (video::Decoder*)ret); 744 | return 1; 745 | } 746 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 747 | } 748 | int lua_cc_video_Player_saveCurrentFrame(lua_State* tolua_S) 749 | { 750 | bool ok = true; 751 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 752 | constexpr auto LUA_FNAME = "video.Player:saveCurrentFrame"; 753 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 754 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 755 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 756 | const int argc = lua_gettop(tolua_S) - 1; 757 | if (argc == 1) { 758 | std::string arg0; 759 | ok &= luaval_to_std_string(tolua_S, 2, &arg0, LUA_FNAME); 760 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 761 | cobj->saveCurrentFrame(arg0); 762 | lua_settop(tolua_S, 1); 763 | return 1; 764 | } 765 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 766 | } 767 | int lua_cc_video_Player_seek(lua_State* tolua_S) 768 | { 769 | bool ok = true; 770 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 771 | constexpr auto LUA_FNAME = "video.Player:seek"; 772 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 773 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 774 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 775 | const int argc = lua_gettop(tolua_S) - 1; 776 | if (argc == 1) { 777 | unsigned int arg0; 778 | ok &= luaval_to_uint32(tolua_S, 2, &arg0, LUA_FNAME); 779 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 780 | cobj->seek(arg0); 781 | lua_settop(tolua_S, 1); 782 | return 1; 783 | } 784 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 785 | } 786 | int lua_cc_video_Player_setAutoRemove(lua_State* tolua_S) 787 | { 788 | bool ok = true; 789 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 790 | constexpr auto LUA_FNAME = "video.Player:setAutoRemove"; 791 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 792 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 793 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 794 | const int argc = lua_gettop(tolua_S) - 1; 795 | if (argc == 1) { 796 | bool arg0; 797 | ok &= luaval_to_boolean(tolua_S, 2, &arg0, LUA_FNAME); 798 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 799 | cobj->setAutoRemove(arg0); 800 | lua_settop(tolua_S, 1); 801 | return 1; 802 | } 803 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 804 | } 805 | int lua_cc_video_Player_setPlayMode(lua_State* tolua_S) 806 | { 807 | bool ok = true; 808 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 809 | constexpr auto LUA_FNAME = "video.Player:setPlayMode"; 810 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 811 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 812 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 813 | const int argc = lua_gettop(tolua_S) - 1; 814 | if (argc == 1) { 815 | video::Player::PlayMode arg0; 816 | int arg0_tmp; ok &= luaval_to_int32(tolua_S, 2, &arg0_tmp, LUA_FNAME); arg0 = (video::Player::PlayMode)arg0_tmp; 817 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 818 | cobj->setPlayMode(arg0); 819 | lua_settop(tolua_S, 1); 820 | return 1; 821 | } 822 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 823 | } 824 | int lua_cc_video_Player_setStep(lua_State* tolua_S) 825 | { 826 | bool ok = true; 827 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 828 | constexpr auto LUA_FNAME = "video.Player:setStep"; 829 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 830 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 831 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 832 | const int argc = lua_gettop(tolua_S) - 1; 833 | if (argc == 1) { 834 | double arg0; 835 | ok &= luaval_to_number(tolua_S, 2, &arg0, LUA_FNAME); 836 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 837 | cobj->setStep(arg0); 838 | lua_settop(tolua_S, 1); 839 | return 1; 840 | } 841 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 842 | } 843 | int lua_cc_video_Player_setVideoEndCallback(lua_State* tolua_S) 844 | { 845 | bool ok = true; 846 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 847 | constexpr auto LUA_FNAME = "video.Player:setVideoEndCallback"; 848 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 849 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 850 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 851 | const int argc = lua_gettop(tolua_S) - 1; 852 | if (argc == 1) { 853 | std::function arg0; 854 | int handler2 = toluafix_ref_function(tolua_S, 2, 0); 855 | ok &= handler2 != 0; 856 | if(ok) 857 | { 858 | arg0 = [=]() 859 | { 860 | toluafix_get_function_by_refid(tolua_S, handler2); 861 | if (!lua_isfunction(tolua_S, -1)) 862 | { 863 | lua_pop(tolua_S, 1); 864 | return ; 865 | } 866 | lua_call(tolua_S, 0, 0); 867 | }; 868 | }; 869 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 870 | cobj->setVideoEndCallback(arg0); 871 | lua_settop(tolua_S, 1); 872 | return 1; 873 | } 874 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "1"); 875 | } 876 | int lua_cc_video_Player_vpause(lua_State* tolua_S) 877 | { 878 | bool ok = true; 879 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 880 | constexpr auto LUA_FNAME = "video.Player:vpause"; 881 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 882 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 883 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 884 | const int argc = lua_gettop(tolua_S) - 1; 885 | if (argc == 0) { 886 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 887 | cobj->vpause(); 888 | lua_settop(tolua_S, 1); 889 | return 1; 890 | } 891 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 892 | } 893 | int lua_cc_video_Player_vplay(lua_State* tolua_S) 894 | { 895 | bool ok = true; 896 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 897 | constexpr auto LUA_FNAME = "video.Player:vplay"; 898 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 899 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 900 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 901 | const int argc = lua_gettop(tolua_S) - 1; 902 | if (argc == 0) { 903 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 904 | cobj->vplay(); 905 | lua_settop(tolua_S, 1); 906 | return 1; 907 | } 908 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 909 | } 910 | int lua_cc_video_Player_vresume(lua_State* tolua_S) 911 | { 912 | bool ok = true; 913 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 914 | constexpr auto LUA_FNAME = "video.Player:vresume"; 915 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 916 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 917 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 918 | const int argc = lua_gettop(tolua_S) - 1; 919 | if (argc == 0) { 920 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 921 | cobj->vresume(); 922 | lua_settop(tolua_S, 1); 923 | return 1; 924 | } 925 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 926 | } 927 | int lua_cc_video_Player_vstop(lua_State* tolua_S) 928 | { 929 | bool ok = true; 930 | constexpr auto LUA_OBJ_TYPE = "video.Player"; 931 | constexpr auto LUA_FNAME = "video.Player:vstop"; 932 | LUA_CHECK_COBJ_TYPE(tolua_S, LUA_OBJ_TYPE, LUA_FNAME); 933 | auto cobj = (video::Player*)tolua_tousertype(tolua_S, 1, nullptr); 934 | LUA_CHECK_COBJ(tolua_S, cobj, LUA_FNAME); 935 | const int argc = lua_gettop(tolua_S) - 1; 936 | if (argc == 0) { 937 | LUA_CHECK_PARAMETER(tolua_S, ok, LUA_FNAME); 938 | cobj->vstop(); 939 | lua_settop(tolua_S, 1); 940 | return 1; 941 | } 942 | LUA_PARAMETER_ERROR(tolua_S, LUA_FNAME, argc, "0"); 943 | } 944 | static int lua_cc_video_Player_finalize(lua_State* tolua_S) 945 | { 946 | return 0; 947 | } 948 | 949 | int lua_register_cc_video_Player(lua_State* tolua_S) 950 | { 951 | tolua_usertype(tolua_S, "video.Player"); 952 | tolua_cclass(tolua_S, "Player", "video.Player", "cc.Sprite", nullptr); 953 | 954 | tolua_beginmodule(tolua_S, "Player"); 955 | tolua_function(tolua_S, "getDecoder", lua_cc_video_Player_getDecoder); 956 | tolua_function(tolua_S, "saveCurrentFrame", lua_cc_video_Player_saveCurrentFrame); 957 | tolua_function(tolua_S, "seek", lua_cc_video_Player_seek); 958 | tolua_function(tolua_S, "setAutoRemove", lua_cc_video_Player_setAutoRemove); 959 | tolua_function(tolua_S, "setPlayMode", lua_cc_video_Player_setPlayMode); 960 | tolua_function(tolua_S, "setStep", lua_cc_video_Player_setStep); 961 | tolua_function(tolua_S, "setVideoEndCallback", lua_cc_video_Player_setVideoEndCallback); 962 | tolua_function(tolua_S, "vpause", lua_cc_video_Player_vpause); 963 | tolua_function(tolua_S, "vplay", lua_cc_video_Player_vplay); 964 | tolua_function(tolua_S, "vresume", lua_cc_video_Player_vresume); 965 | tolua_function(tolua_S, "vstop", lua_cc_video_Player_vstop); 966 | tolua_function(tolua_S, "create", lua_cc_video_Player_create); 967 | { 968 | tolua_module(tolua_S, "PlayMode", 0); 969 | tolua_beginmodule(tolua_S, "PlayMode"); 970 | { 971 | tolua_constant(tolua_S, "STEP", (lua_Number)video::Player::PlayMode::STEP); 972 | tolua_constant(tolua_S, "REALTIME", (lua_Number)video::Player::PlayMode::REALTIME); 973 | tolua_constant(tolua_S, "FRAME", (lua_Number)video::Player::PlayMode::FRAME); 974 | tolua_constant(tolua_S, "MANUAL", (lua_Number)video::Player::PlayMode::MANUAL); 975 | } 976 | tolua_endmodule(tolua_S); 977 | } 978 | tolua_endmodule(tolua_S); 979 | const auto typeName = reinterpret_cast(typeid(video::Player).name()); 980 | g_luaType[typeName] = "video.Player"; 981 | g_typeCast["Player"] = "video.Player"; 982 | return 1; 983 | } 984 | 985 | int register_all_cc_video(lua_State* tolua_S) 986 | { 987 | tolua_open(tolua_S); 988 | 989 | tolua_module(tolua_S, "video", 0); 990 | tolua_beginmodule(tolua_S, "video"); 991 | 992 | lua_register_cc_video_Player(tolua_S); 993 | lua_register_cc_video_Decoder(tolua_S); 994 | 995 | tolua_endmodule(tolua_S); 996 | return 1; 997 | } 998 | 999 | -------------------------------------------------------------------------------- /lua_video_auto.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef __cplusplus 3 | extern "C" { 4 | #endif 5 | #include "tolua++.h" 6 | #ifdef __cplusplus 7 | } 8 | #endif 9 | 10 | int register_all_cc_video(lua_State* tolua_S); 11 | 12 | --------------------------------------------------------------------------------