1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
#ifndef VIDEOPLAYER_VIDEOSTATE_H
#define VIDEOPLAYER_VIDEOSTATE_H
#include <cstdint>
#include <atomic>
#include <array>
#include <vector>
#include <memory>
#include <string>
#include <mutex>
#include <condition_variable>
#include <osg/ref_ptr>
namespace osg
{
class Texture2D;
}
#if defined(_MSC_VER)
#pragma warning (push)
#pragma warning (disable : 4244)
#endif
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/channel_layout.h>
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
// https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d
// https://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872
#include <libswresample/swresample.h>
}
#if defined(_MSC_VER)
#pragma warning (pop)
#endif
#include "videodefs.hpp"
#include "libavformatdefines.hpp"
#define VIDEO_PICTURE_QUEUE_SIZE 50
extern "C"
{
struct SwsContext;
struct AVPacket;
struct AVFormatContext;
struct AVStream;
struct AVFrame;
}
namespace Video
{
struct VideoState;
class MovieAudioFactory;
class MovieAudioDecoder;
class VideoThread;
class ParseThread;
struct ExternalClock
{
ExternalClock();
uint64_t mTimeBase;
uint64_t mPausedAt;
bool mPaused;
std::mutex mMutex;
void setPaused(bool paused);
uint64_t get();
void set(uint64_t time);
};
class PacketList
{
public:
AVPacket* pkt = nullptr;
PacketList *next = nullptr;
};
struct PacketQueue {
PacketQueue()
: first_pkt(nullptr), last_pkt(nullptr), flushing(false), nb_packets(0), size(0)
{ }
~PacketQueue()
{ clear(); }
PacketList *first_pkt, *last_pkt;
std::atomic<bool> flushing;
std::atomic<int> nb_packets;
std::atomic<int> size;
std::mutex mutex;
std::condition_variable cond;
void put(AVPacket *pkt);
int get(AVPacket *pkt, VideoState *is);
void flush();
void clear();
};
struct VideoPicture {
VideoPicture() : pts(0.0)
{ }
struct AVFrameDeleter {
void operator()(AVFrame* frame) const;
};
// Sets frame dimensions.
// Must be called before writing to `rgbaFrame`.
// Return -1 on error.
int set_dimensions(int w, int h);
std::unique_ptr<AVFrame, AVFrameDeleter> rgbaFrame;
double pts;
};
struct VideoState {
VideoState();
~VideoState();
void setAudioFactory(MovieAudioFactory* factory);
void init(std::unique_ptr<std::istream>&& inputstream, const std::string& name);
void deinit();
void setPaused(bool isPaused);
void seekTo(double time);
double getDuration() const;
int stream_open(int stream_index, AVFormatContext *pFormatCtx);
bool update();
static void video_thread_loop(VideoState *is);
static void decode_thread_loop(VideoState *is);
void video_display(VideoPicture* vp);
void video_refresh();
int queue_picture(const AVFrame &pFrame, double pts);
double synchronize_video(const AVFrame &src_frame, double pts);
double get_audio_clock();
double get_video_clock() const;
double get_external_clock();
double get_master_clock();
static int istream_read(void *user_data, uint8_t *buf, int buf_size);
#if OPENMW_FFMPEG_CONST_WRITEPACKET
static int istream_write(void *, const unsigned char *, int);
#else
static int istream_write(void *, uint8_t *, int);
#endif
static int64_t istream_seek(void *user_data, int64_t offset, int whence);
osg::ref_ptr<osg::Texture2D> mTexture;
MovieAudioFactory* mAudioFactory;
std::unique_ptr<MovieAudioDecoder> mAudioDecoder;
ExternalClock mExternalClock;
std::unique_ptr<std::istream> stream;
AVFormatContext* format_ctx;
AVCodecContext* video_ctx;
AVCodecContext* audio_ctx;
int av_sync_type;
AVStream** audio_st;
PacketQueue audioq;
uint8_t* mFlushPktData;
AVStream** video_st;
double frame_last_pts;
double video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
PacketQueue videoq;
SwsContext* sws_context;
int sws_context_w, sws_context_h;
std::array<VideoPicture, VIDEO_PICTURE_QUEUE_SIZE+1> pictq; // allocate one extra to make sure we do not overwrite the osg::Image currently set on the texture
int pictq_size;
unsigned long pictq_rindex, pictq_windex;
std::mutex pictq_mutex;
std::condition_variable pictq_cond;
std::unique_ptr<ParseThread> parse_thread;
std::unique_ptr<VideoThread> video_thread;
std::atomic<bool> mSeekRequested;
uint64_t mSeekPos;
std::atomic<bool> mVideoEnded;
std::atomic<bool> mPaused;
std::atomic<bool> mQuit;
};
}
#endif
|