Files
fmviewer3/project/fm_viewer/fav/AVDemuxer.h
2026-02-21 17:11:31 +09:00

250 lines
8.9 KiB
C++

/******************************************************************************
QtAV: Media play library based on Qt and FFmpeg
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
* This file is part of QtAV
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/
#ifndef QAV_DEMUXER_H
#define QAV_DEMUXER_H
#include "AVError.h"
#include "Packet.h"
#include <QtCore/QVariant>
#include <QtCore/QObject>
#include <QtCore/QScopedPointer>
struct AVFormatContext;
struct AVCodecContext;
QT_BEGIN_NAMESPACE
class QIODevice;
QT_END_NAMESPACE
// TODO: force codec name. clean code
namespace FAV {
class AVError;
class MediaIO;
class Q_AV_EXPORT AVDemuxer : public QObject
{
Q_OBJECT
public:
enum StreamType { //TODO: move to common MediaType
AudioStream,
VideoStream,
#if !(DO_NOT_USE_SUBTITLE)
SubtitleStream,
#endif
};
static const QStringList& supportedFormats();
static const QStringList& supportedExtensions();
/// Supported ffmpeg/libav input protocols(not complete). A static string list
static const QStringList& supportedProtocols();
AVDemuxer(QObject *parent = 0);
~AVDemuxer();
int playerID;
#if (REAR_SYNC_FRONT)
double rear_delay;
#endif
qint64 _lastDuration;
#if (FIXED_FPS_DURATION)
qint64 durationFixed;
qint32 frameCount;
#if (FORCE_BREAK_EOF)
qint64 endFilePosition; // 시간(DTS/PTS)으로 EOF 처리 불가능함 -> 파일 포지션으로 처리
#endif // FORCE_BREAK_EOF
#if (PREVENT_OVER_DURATION_RENDER)
qint64 originalDuraiont; // VideoThread 에 전달하여 원 재생시간 이상의 경우 DRAW 하지 않도록 변경
#endif // PREVENT_OVER_DURATION_RENDER
#endif //FIXED_FPS_DURATION
qint32 realVideoStreamCount; ///!< 실제(프레임이 존재하는) 비디오 스트림 개수
#if (PLAY_SYNC_FIX2)
qint64 frameDuration; // 각 프레임당 길이(SEEK 및 SLIDER BAR 계산시 durationFixed - frameDuration 으로 사용)
#endif // PLAY_SYNC_FIX2
MediaStatus mediaStatus() const;
bool atEnd() const;
QString fileName() const;
QIODevice* ioDevice() const;
/// not null for QIODevice, custom protocols
MediaIO* mediaIO() const;
/*!
* \brief setMedia
* \return whether the media source is changed
*/
bool setMedia(const QString& fileName);
bool setMedia(QIODevice* dev);
bool setMedia(MediaIO* in);
/*!
* \brief setFormat
* Force the input format. Useful if input stream is a raw video stream(fmt="rawvideo).
* formatForced() is reset if media changed. So you have to call setFormat() for every media
* you want to force the format.
* If AVFormatContext.format_whitelist contains only 1 format, then that format will be forced.
* For example, setOptions({"format_whitelist": "rawvideo"})
*/
void setFormat(const QString& fmt);
QString formatForced() const;
bool load();
bool unload();
bool isLoaded() const;
/*!
* \brief readFrame
* Read a packet from 1 of the streams. use packet() to get the result packet. packet() returns last valid packet.
* So do not use packet() if readFrame() failed.
* Call readFrame() and seek() in the same thread.
* \return true if no error. false if error occurs, eof reaches, interrupted by user or time out(getInterruptTimeout())
*/
bool readFrame(); // TODO: rename int readPacket(), return stream number
/*!
* \brief packet
* return the packet read by demuxer. packet is invalid if readFrame() returns false.
*/
Packet packet() const;
/*!
* \brief stream
* Current readFrame() readed stream index.
*/
int stream() const;
bool isSeekable() const; // TODO: change in unload?
void setSeekUnit(SeekUnit unit);
SeekUnit seekUnit() const;
void setSeekType(SeekType target);
SeekType seekType() const;
/*!
* \brief seek
* seek to a given position. Only support timestamp seek now.
* Experiment: if pos is out of range (>duration()), do nothing unless a seekable and variableSize MediaIO is used.
* \return false if fail
*/
bool seek(qint64 pos); //pos: ms
/*!
* \brief seek
* Percentage seek. duration() must be >0LL
* \param q [0, 1]
* TODO: what if duration() is not valid but size is known?
*/
bool seek(qreal q);
AVFormatContext* formatContext();
QString formatName() const;
QString formatLongName() const;
// TODO: rename startPosition()
qint64 startTime() const; //ms, AVFormatContext::start_time/1000
qint64 duration() const; //ms, AVFormatContext::duration/1000
qint64 startTimeUs() const; //us, AVFormatContext::start_time
qint64 durationUs() const; //us, AVFormatContext::duration
qint64 durationUSAudio() const; // Audio duration
//total bit rate
int bitRate() const; //AVFormatContext::bit_rate
qreal frameRate() const; //deprecated AVStream::avg_frame_rate
// if stream is -1, return the current video(or audio if no video) stream.
// TODO: audio/videoFrames?
qint64 frames(int stream = -1) const; //AVFormatContext::nb_frames
bool hasAttacedPicture() const;
/*!
* \brief setStreamIndex
* Set stream by index in stream list. call it after loaded.
* Stream/index will not change in next load() unless media source changed
* index < 0 is invalid
*/
bool setStreamIndex(StreamType st, int index);
// current open stream
int currentStream(StreamType st) const;
QList<int> streams(StreamType st) const;
// TODO: stream(StreamType), streams(StreamType)
// current open stream
int audioStream() const;
QList<int> audioStreams() const;
int videoStream() const;
QList<int> videoStreams() const;
int subtitleStream() const;
QList<int> subtitleStreams() const;
//codec. stream < 0: the stream going to play (or the stream set by setStreamIndex())
AVCodecContext* audioCodecContext(int stream = -1) const;
AVCodecContext* videoCodecContext(int stream = -1) const;
AVCodecContext* subtitleCodecContext(int stream = -1) const;
/**
* @brief getInterruptTimeout return the interrupt timeout
*/
qint64 getInterruptTimeout() const;
/**
* @brief setInterruptTimeout set the interrupt timeout
* @param timeout in ms
*/
void setInterruptTimeout(qint64 timeout);
bool isInterruptOnTimeout() const;
void setInterruptOnTimeout(bool value);
/**
* @brief getInterruptStatus return the interrupt status.
* \return -1: interrupted by user
* 0: not interrupted
* >0: timeout value of AVError::ErrorCode
*/
int getInterruptStatus() const;
/**
* @brief setInterruptStatus set the interrupt status
* @param interrupt <0: abort current operation like loading and reading packets.
* 0: no interrupt
*/
void setInterruptStatus(int interrupt);
/*!
* \brief setOptions
* libav's AVDictionary. we can ignore the flags used in av_dict_xxx because we can use hash api.
* empty value does nothing to current context if it is open, but will change AVDictionary options to null in next open.
* AVDictionary is used in avformat_open_input() and will not change unless user call setOptions()
* If an option is not found
*/
void setOptions(const QVariantHash &dict);
QVariantHash options() const;
Q_SIGNALS:
void unloaded();
void userInterrupted(); // NO direct connection because it's emit before interrupted happens
void loaded();
// emit when the first frame is read
void started();
void finished(); //end of file
void error(const FAV::AVError& e); //explictly use FAV::AVError in connection for Qt4 syntax
void mediaStatusChanged(FAV::MediaStatus status);
void seekableChanged();
#if (FIXED_FPS_DURATION)
void mediaEnded();
#endif
private:
void setMediaStatus(MediaStatus status);
// error code (errorCode) and message (msg) may be modified internally
void handleError(int averr, AVError::ErrorCode* errorCode, QString& msg);
class Private;
QScopedPointer<Private> d;
class InterruptHandler;
friend class InterruptHandler;
#if (FIXED_FPS_DURATION)
void _loadDuration();
#endif
};
} //namespace FAV
#endif // QAV_DEMUXER_H