diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-09-15 11:33:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-09-15 11:33:30 -0300 |
commit | 8cab401d08f8e25aa9b2dc710204785858ff3dbb (patch) | |
tree | 1a4cec868f937fb24d340ee33fbeba2f1c6fa9f2 /drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp | |
parent | 1a2cb755e2d8b9d59178f36702f6dff7235b9088 (diff) |
3D Physics Rework, Other Stuff
-=-=-=-=-=-=-=-=-=-=-=-=-=-
3D Physics:
-Fixed "Bounce" parameter in 3D
-Fixed bug affecting Area (sometims it would not detect properly)
-Vehicle Body has seen heavy work
-Added Query API for doing space queries in 3D. Needs some docs though.
-Added JOINTS! Adapted Bullet Joints: and created easy gizmos for setting them up:
-PinJoint
-HingeJoint (with motor)
-SliderJoint
-ConeTwistJoint
-Generic6DOFJoint
-Added OBJECT PICKING! based on the new query API. Any physics object now (Area or Body) has the following signals and virtual functions:
-input_event (mouse or multitouch input over the body)
-mouse_enter (mouse entered the body area)
-mouse_exit (mouse exited body area)
For Area it needs to be activated manually, as it isn't by default (ray goes thru).
Other:
-Begun working on Windows 8 (RT) port. Compiles but does not work yet.
-Added TheoraPlayer library for improved to-texture and portable video support.
-Fixed a few bugs in the renderer, collada importer, collada exporter, etc.
Diffstat (limited to 'drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp')
-rw-r--r-- | drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp b/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp new file mode 100644 index 0000000000..fa3fd43a47 --- /dev/null +++ b/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp @@ -0,0 +1,439 @@ +/************************************************************************************ +This source file is part of the Theora Video Playback Library +For latest info, see http://libtheoraplayer.googlecode.com +************************************************************************************* +Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com) +This program is free software; you can redistribute it and/or modify it under +the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause +*************************************************************************************/ +#ifdef __FFMPEG +#include "TheoraAudioInterface.h" +#include "TheoraDataSource.h" +#include "TheoraException.h" +#include "TheoraTimer.h" +#include "TheoraUtil.h" +#include "TheoraFrameQueue.h" +#include "TheoraVideoFrame.h" +#include "TheoraVideoManager.h" +#include "TheoraVideoClip_FFmpeg.h" +#include "TheoraPixelTransform.h" + +#define READ_BUFFER_SIZE 4096 + +#ifdef __cplusplus +#define __STDC_CONSTANT_MACROS +#ifdef _STDINT_H +#undef _STDINT_H +#endif +# include <stdint.h> +#endif + +#define _FFMPEG_DEBUG + +extern "C" +{ +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> +#include "libavutil/avassert.h" +} + +static bool ffmpegInitialised = 0; + +static int readFunction(void* data, uint8_t* buf, int buf_size) +{ +#ifdef _FFMPEG_DEBUG + th_writelog("reading " + str(buf_size) + " bytes"); +#endif + + TheoraDataSource* src = (TheoraDataSource*) data; + return src->read(buf, buf_size); +} + +static int64_t seekFunction(void* data, int64_t offset, int whence) +{ +#ifdef _FFMPEG_DEBUG + th_writelog("seeking: offset = " + str((long) offset) + ", whence = " + str(whence)); +#endif + + TheoraDataSource* src = (TheoraDataSource*) data; + if (whence == AVSEEK_SIZE) + return src->size(); + else if (whence == SEEK_SET) + src->seek((long) offset); + else if (whence == SEEK_END) + src->seek(src->size() - (long) offset); + return src->tell(); +} + +static void avlog_theoraplayer(void* p, int level, const char* fmt, va_list vargs) +{ + th_writelog(fmt); + static char logstr[2048]; + vsprintf(logstr, fmt, vargs); + th_writelog("ffmpeg: " + std::string(logstr)); +} + + +std::string text; + +static void _log(const char* s) +{ + text += s; +// th_writelog(text); +// text = ""; +} + +static void _log(const char c) +{ + char s[2] = {c, 0}; + _log(s); +} + +static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev, + int encoder) +{ + while ((prev = av_codec_next(prev))) { + if (prev->id == id && + (encoder ? av_codec_is_encoder(prev) : av_codec_is_decoder(prev))) + return prev; + } + return NULL; +} + +static int compare_codec_desc(const void *a, const void *b) +{ + const AVCodecDescriptor **da = (const AVCodecDescriptor **) a; + const AVCodecDescriptor **db = (const AVCodecDescriptor **) b; + + return (*da)->type != (*db)->type ? (*da)->type - (*db)->type : + strcmp((*da)->name, (*db)->name); +} + +static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs) +{ + const AVCodecDescriptor *desc = NULL; + const AVCodecDescriptor **codecs; + unsigned nb_codecs = 0, i = 0; + + while ((desc = avcodec_descriptor_next(desc))) + ++nb_codecs; + if (!(codecs = (const AVCodecDescriptor**) av_calloc(nb_codecs, sizeof(*codecs)))) { + av_log(NULL, AV_LOG_ERROR, "Out of memory\n"); + exit(1); + } + desc = NULL; + while ((desc = avcodec_descriptor_next(desc))) + codecs[i++] = desc; + av_assert0(i == nb_codecs); + qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc); + *rcodecs = codecs; + return nb_codecs; +} + +static char get_media_type_char(enum AVMediaType type) +{ + switch (type) { + case AVMEDIA_TYPE_VIDEO: return 'V'; + case AVMEDIA_TYPE_AUDIO: return 'A'; + case AVMEDIA_TYPE_DATA: return 'D'; + case AVMEDIA_TYPE_SUBTITLE: return 'S'; + case AVMEDIA_TYPE_ATTACHMENT:return 'T'; + default: return '?'; + } +} + +static void print_codecs_for_id(enum AVCodecID id, int encoder) +{ + const AVCodec *codec = NULL; + + _log(encoder ? "encoders" : "decoders"); + + while ((codec = next_codec_for_id(id, codec, encoder))) + _log(codec->name); + + _log(")"); +} + +int show_codecs(void *optctx, const char *opt, const char *arg) +{ + const AVCodecDescriptor **codecs; + unsigned i, nb_codecs = get_codecs_sorted(&codecs); + + char tmp[1024]; + th_writelog("Codecs:\n" + " D..... = Decoding supported\n" + " .E.... = Encoding supported\n" + " ..V... = Video codec\n" + " ..A... = Audio codec\n" + " ..S... = Subtitle codec\n" + " ...I.. = Intra frame-only codec\n" + " ....L. = Lossy compression\n" + " .....S = Lossless compression\n" + " -------\n"); + for (i = 0; i < nb_codecs; ++i) { + const AVCodecDescriptor *desc = codecs[i]; + const AVCodec *codec = NULL; + + _log(" "); + _log(avcodec_find_decoder(desc->id) ? "D" : "."); + _log(avcodec_find_encoder(desc->id) ? "E" : "."); + + _log(get_media_type_char(desc->type)); + _log((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : "."); + _log((desc->props & AV_CODEC_PROP_LOSSY) ? "L" : "."); + _log((desc->props & AV_CODEC_PROP_LOSSLESS) ? "S" : "."); + + + sprintf(tmp, " %-20s %s", desc->name, desc->long_name ? desc->long_name : ""); + + _log(tmp); + /* print decoders/encoders when there's more than one or their + * names are different from codec name */ + while ((codec = next_codec_for_id(desc->id, codec, 0))) { + if (strcmp(codec->name, desc->name)) { + print_codecs_for_id(desc->id, 0); + break; + } + } + codec = NULL; + while ((codec = next_codec_for_id(desc->id, codec, 1))) { + if (strcmp(codec->name, desc->name)) { + print_codecs_for_id(desc->id, 1); + break; + } + } + _log("\n"); + } + av_free(codecs); + + av_log(0, 0, "%s", text.c_str()); + return 0; +} + +TheoraVideoClip_FFmpeg::TheoraVideoClip_FFmpeg(TheoraDataSource* data_source, + TheoraOutputMode output_mode, + int nPrecachedFrames, + bool usePower2Stride): + TheoraVideoClip(data_source, output_mode, nPrecachedFrames, usePower2Stride), + TheoraAudioPacketQueue() +{ + mFormatContext = NULL; + mCodecContext = NULL; + mCodec = NULL; + mFrame = NULL; + mVideoStreamIndex = -1; +} + +TheoraVideoClip_FFmpeg::~TheoraVideoClip_FFmpeg() +{ + unload(); +} + +void TheoraVideoClip_FFmpeg::load(TheoraDataSource* source) +{ + mVideoStreamIndex = -1; + mFrameNumber = 0; + AVDictionary* optionsDict = NULL; + + if (!ffmpegInitialised) + { +#ifdef _FFMPEG_DEBUG + th_writelog("Initializing ffmpeg"); +#endif + th_writelog("avcodec version: " + str(avcodec_version())); + av_register_all(); + av_log_set_level(AV_LOG_DEBUG); + av_log_set_callback(avlog_theoraplayer); + ffmpegInitialised = 1; + //show_codecs(0, 0, 0); + } + + mInputBuffer = (unsigned char*) av_malloc(READ_BUFFER_SIZE); + mAvioContext = avio_alloc_context(mInputBuffer, READ_BUFFER_SIZE, 0, source, &readFunction, NULL, &seekFunction); + +#ifdef _FFMPEG_DEBUG + th_writelog(mName + ": avio context created"); +#endif + + mFormatContext = avformat_alloc_context(); +#ifdef _FFMPEG_DEBUG + th_writelog(mName + ": avformat context created"); +#endif + mFormatContext->pb = mAvioContext; + + int err; + if ((err = avformat_open_input(&mFormatContext, "", NULL, NULL)) != 0) + { + th_writelog(mName + ": avformat input opening failed!"); + th_writelog(mName + ": error_code: " + str(err)); + return; + } + +#ifdef _FFMPEG_DEBUG + th_writelog(mName + ": avformat input opened"); +#endif + + // Retrieve stream information + if (avformat_find_stream_info(mFormatContext, NULL) < 0) + return; // Couldn't find stream information + +#ifdef _FFMPEG_DEBUG + th_writelog(mName + ": got stream info"); +#endif + + // Dump information about file onto standard error + // av_dump_format(mFormatContext, 0, "", 0); + + // Find the first video stream + for (int i = 0; i < mFormatContext->nb_streams; ++i) + { + if(mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) + { + mVideoStreamIndex = i; + break; + } + } + if (mVideoStreamIndex == -1) + return; // Didn't find a video stream + +#ifdef _FFMPEG_DEBUG + th_writelog(mName + ": Found video stream at index " + str(mVideoStreamIndex)); +#endif + + // Get a pointer to the codec context for the video stream + mCodecContext = mFormatContext->streams[mVideoStreamIndex]->codec; + + // Find the decoder for the video stream + mCodec = avcodec_find_decoder(mCodecContext->codec_id); + if (mCodec == NULL) + { + th_writelog("Unsupported codec!"); + return; // Codec not found + } + // Open codec + if(avcodec_open2(mCodecContext, mCodec, &optionsDict) < 0) + return; // Could not open codec + +#ifdef _FFMPEG_DEBUG + th_writelog(mName + ": Codec opened"); +#endif + + + mFrame = avcodec_alloc_frame(); + +#ifdef _FFMPEG_DEBUG + th_writelog(mName + ": Frame allocated"); +#endif + + //AVRational rational = mCodecContext->time_base; + + mFPS = 25; //TODOOOOOO!!! + + mWidth = mStride = mCodecContext->width; + mHeight = mCodecContext->height; + mFrameDuration = 1.0f / mFPS; + mDuration = mFormatContext->duration / AV_TIME_BASE; + + if (mFrameQueue == NULL) // todo - why is this set in the backend class? it should be set in the base class, check other backends as well + { + mFrameQueue = new TheoraFrameQueue(this); + mFrameQueue->setSize(mNumPrecachedFrames); + } +} + +void TheoraVideoClip_FFmpeg::unload() +{ + if (mInputBuffer) + { +// av_free(mInputBuffer); + mInputBuffer = NULL; + } + if (mAvioContext) + { + av_free(mAvioContext); + mAvioContext = NULL; + } + if (mFrame) + { + av_free(mFrame); + mFrame = NULL; + } + if (mCodecContext) + { + avcodec_close(mCodecContext); + mCodecContext = NULL; + } + if (mFormatContext) + { + avformat_close_input(&mFormatContext); + mFormatContext = NULL; + } +} + +bool TheoraVideoClip_FFmpeg::_readData() +{ + return 1; +} + +bool TheoraVideoClip_FFmpeg::decodeNextFrame() +{ + TheoraVideoFrame* frame = mFrameQueue->requestEmptyFrame(); + if (!frame) return 0; + + AVPacket packet; + int frameFinished; + + while (av_read_frame(mFormatContext, &packet) >= 0) + { + if (packet.stream_index == mVideoStreamIndex) + { + avcodec_decode_video2(mCodecContext, mFrame, &frameFinished, &packet); + + if (frameFinished) + { + TheoraPixelTransform t; + memset(&t, 0, sizeof(TheoraPixelTransform)); + + t.y = mFrame->data[0]; t.yStride = mFrame->linesize[0]; + t.u = mFrame->data[1]; t.uStride = mFrame->linesize[1]; + t.v = mFrame->data[2]; t.vStride = mFrame->linesize[2]; + + frame->decode(&t); + frame->mTimeToDisplay = mFrameNumber / mFPS; + frame->mIteration = mIteration; + frame->_setFrameNumber(mFrameNumber++); + + av_free_packet(&packet); + break; + } + } + av_free_packet(&packet); + } + return 1; +} + +void TheoraVideoClip_FFmpeg::decodedAudioCheck() +{ + if (!mAudioInterface || mTimer->isPaused()) return; + + mAudioMutex->lock(); + flushAudioPackets(mAudioInterface); + mAudioMutex->unlock(); +} + +float TheoraVideoClip_FFmpeg::decodeAudio() +{ + return -1; +} + +void TheoraVideoClip_FFmpeg::doSeek() +{ + +} + +void TheoraVideoClip_FFmpeg::_restart() +{ + +} + +#endif |