Skip to content

Commit

Permalink
#49 Full support for selecting the media streams before beginning the…
Browse files Browse the repository at this point in the history
… playback
  • Loading branch information
Ceylo committed Sep 3, 2014
1 parent 7720d38 commit 4a227ac
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 74 deletions.
29 changes: 21 additions & 8 deletions include/sfeMovie/Movie.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,22 @@ namespace sfe {
Video,
Unknown
};

struct StreamDescriptor {
int index; //!< Stream index in the media, used for choosing which stream to enable

struct SFE_API StreamDescriptor {
/** Return a stream descriptor that identifies no stream. This allows disabling a specific stream kind
*
* @param type the stream kind (audio, video...) to disable
* @return a StreamDescriptor that can be used to disable the given stream kind
*/
static StreamDescriptor NoSelection(MediaType type);

MediaType type; //!< Stream kind: video, audio or subtitle
int identifier; //!< Stream identifier in the media, used for choosing which stream to enable
std::string language; //!< Language code defined by ISO 639-2, if set by the media
};

typedef std::vector<StreamDescriptor> Streams;

class SFE_API Movie : public sf::Drawable, public sf::Transformable {
public:
Movie();
Expand All @@ -71,19 +80,23 @@ namespace sfe {
*/
bool openFromFile(const std::string& filename);

/** Return a description of all the streams contained in the opened media
/** Return a description of all the streams of the given type contained in the opened media
*
* @param type the stream type (audio, video...) to return
*/
const std::vector<StreamDescriptor>& getStreams() const;
const Streams& getStreams(MediaType type) const;

/** Request activation of the given stream. In case another stream of the same kind is already active,
* it is deactivated.
*
* @note When opening a new media file, the default behaviour is to automatically activate the first
* @note When opening a new media file, the default behaviour is to automatically activate the first
* found audio and video streams
*
* @warning This method can only be used when the movie is stopped
*
* @param stream the stream descriptor of the stream to activate
* @param streamDescriptor the descriptor of the stream to activate
*/
void selectStream(const StreamDescriptor& stream);
void selectStream(const StreamDescriptor& streamDescriptor);

/** Start or resume playing the media playback
*
Expand Down
44 changes: 36 additions & 8 deletions sample/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,17 @@ void printMovieInfo(const sfe::Movie& movie)
std::cout << "Sample rate: " << movie.getSampleRate() << std::endl;
std::cout << "Channel count: " << movie.getChannelCount() << std::endl;

const std::vector<sfe::StreamDescriptor>& streams = movie.getStreams();
std::cout << streams.size() << " streams found in the media" << std::endl;
const sfe::Streams& videoStreams = movie.getStreams(sfe::Video);
const sfe::Streams& audioStreams = movie.getStreams(sfe::Audio);

std::cout << videoStreams.size() + audioStreams.size() << " streams found in the media" << std::endl;

for (std::vector<sfe::StreamDescriptor>::const_iterator it = streams.begin(); it != streams.end(); ++it) {
std::cout << " #" << it->index << " : " << MediaTypeToString(it->type);
for (sfe::Streams::const_iterator it = videoStreams.begin(); it != videoStreams.end(); ++it) {
std::cout << " #" << it->identifier << " : " << MediaTypeToString(it->type) << std::endl;
}

for (sfe::Streams::const_iterator it = audioStreams.begin(); it != audioStreams.end(); ++it) {
std::cout << " #" << it->identifier << " : " << MediaTypeToString(it->type);

if (!it->language.empty())
std::cout << " (language: " << it->language << ")";
Expand Down Expand Up @@ -122,10 +128,16 @@ int main(int argc, const char *argv[])
sf::RenderWindow window(sf::VideoMode(width, height), "sfeMovie Player",
sf::Style::Close | sf::Style::Resize);
movie.fit(0, 0, width, height);

printMovieInfo(movie);

// Allow stream selection
const sfe::Streams& audioStreams = movie.getStreams(sfe::Audio);
const sfe::Streams& videoStreams = movie.getStreams(sfe::Video);
int selectedVideoStreamId = 0;
int selectedAudioStreamId = 0;

// Scale movie to the window drawing area and enable VSync
window.setFramerateLimit(60);
movie.play();

while (window.isOpen())
{
Expand Down Expand Up @@ -159,15 +171,31 @@ int main(int argc, const char *argv[])
movie.fit(0, 0, window.getSize().x, window.getSize().y);
} else if (ev.key.code == sf::Keyboard::P) {
printMovieInfo(movie);
}
} else if (ev.key.code == sf::Keyboard::V) {
if (videoStreams.size() > 1) {
selectedVideoStreamId++;
selectedVideoStreamId %= videoStreams.size();
movie.selectStream(videoStreams[selectedVideoStreamId]);
std::cout << "Selected video stream #" << videoStreams[selectedVideoStreamId].identifier
<< std::endl;
}
} else if (ev.key.code == sf::Keyboard::A) {
if (audioStreams.size() > 1) {
selectedAudioStreamId++;
selectedAudioStreamId %= audioStreams.size();
movie.selectStream(audioStreams[selectedAudioStreamId]);
std::cout << "Selected audio stream #" << audioStreams[selectedAudioStreamId].identifier
<< std::endl;
}
}
} else if (ev.type == sf::Event::MouseWheelMoved) {
float volume = movie.getVolume() + 10 * ev.mouseWheel.delta;
volume = std::min(volume, 100.f);
volume = std::max(volume, 0.f);
movie.setVolume(volume);
} else if (ev.type == sf::Event::Resized) {
movie.fit(0, 0, window.getSize().x, window.getSize().y);
window.setView(sf::View(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y)));
window.setView(sf::View(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y)));
}
}

Expand Down
25 changes: 15 additions & 10 deletions src/Demuxer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ namespace sfe {
*/

default:
m_ignoredStreams[ffstream->index] = std::string(std::string(av_get_media_type_string(ffstream->codec->codec_type)) + "/" + avcodec_get_name(ffstream->codec->codec_id));
m_ignoredStreams[ffstream->index] = std::string("'" + std::string(av_get_media_type_string(ffstream->codec->codec_type)) + "/" + avcodec_get_name(ffstream->codec->codec_id));
sfeLogDebug(m_ignoredStreams[ffstream->index] + "' stream ignored");
break;
}
Expand Down Expand Up @@ -220,18 +220,20 @@ namespace sfe {
return streamSet;
}

std::vector<StreamDescriptor> Demuxer::computeStreamDescriptors() const
Streams Demuxer::computeStreamDescriptors(MediaType type) const
{
std::vector<StreamDescriptor> entries;
Streams entries;
std::set<Stream*> streamSet;
std::map<int, Stream*>::const_iterator it;

for (it = m_streams.begin(); it != m_streams.end(); it++) {
StreamDescriptor entry;
entry.index = it->first;
entry.language = it->second->getLanguage();
entry.type = it->second->getStreamKind();
entries.push_back(entry);
if (it->second->getStreamKind() == type) {
StreamDescriptor entry;
entry.type = type;
entry.identifier = it->first;
entry.language = it->second->getLanguage();
entries.push_back(entry);
}
}

return entries;
Expand All @@ -240,7 +242,9 @@ namespace sfe {
void Demuxer::selectAudioStream(AudioStream* stream)
{
Status oldStatus = m_timer.getStatus();

CHECK(oldStatus == Stopped, "Changing the selected stream after starting "
"the movie playback isn't supported yet");

if (oldStatus == Playing)
m_timer.pause();

Expand Down Expand Up @@ -274,6 +278,8 @@ namespace sfe {
void Demuxer::selectVideoStream(VideoStream* stream)
{
Status oldStatus = m_timer.getStatus();
CHECK(oldStatus == Stopped, "Changing the selected stream after starting "
"the movie playback isn't supported yet");

if (oldStatus == Playing)
m_timer.pause();
Expand Down Expand Up @@ -330,7 +336,6 @@ namespace sfe {
std::map<int, Stream*> streams = getStreams();
std::map<int, Stream*>::iterator it;

// std::cout << "Timer: " << m_timer.getOffset().asMilliseconds() << " ms" << std::endl;
for (it = streams.begin();it != streams.end(); it++) {
it->second->update();
}
Expand Down
5 changes: 3 additions & 2 deletions src/Demuxer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,12 @@ namespace sfe {
*/
std::set<Stream*> getStreamsOfType(MediaType type) const;

/** Gather the required stream metadata from each stream
/** Gather the required stream metadata from each stream of the given type
*
* @param type the type of the streams that are to be described
* @return the stream entries computed from the gathered metadata
*/
std::vector<StreamDescriptor> computeStreamDescriptors() const;
Streams computeStreamDescriptors(MediaType type) const;

/** Enable the given audio stream and connect it to the reference timer
*
Expand Down
16 changes: 12 additions & 4 deletions src/Movie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@


namespace sfe {
StreamDescriptor StreamDescriptor::NoSelection(sfe::MediaType type)
{
StreamDescriptor descriptor;
descriptor.type = type;
descriptor.identifier = -1;
return descriptor;
}

Movie::Movie() :
m_impl(new MovieImpl(*this))
{
Expand All @@ -43,14 +51,14 @@ namespace sfe {
return m_impl->openFromFile(filename);
}

const std::vector<StreamDescriptor>& Movie::getStreams() const
const Streams& Movie::getStreams(MediaType type) const
{
return m_impl->getStreams();
return m_impl->getStreams(type);
}

void Movie::selectStream(const StreamDescriptor& stream)
void Movie::selectStream(const StreamDescriptor& streamDescriptor)
{
return m_impl->selectStream(stream);
return m_impl->selectStream(streamDescriptor);
}

void Movie::play()
Expand Down
Loading

0 comments on commit 4a227ac

Please sign in to comment.