Media.cpp 6.38 KB
Newer Older
1
/*****************************************************************************
2
 * Media.cpp: Represents a basic container for media informations.
3
 *****************************************************************************
4
 * Copyright (C) 2008-2016 VideoLAN
5
 *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
6
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
7
 *          Yikei Lu    <luyikei.qmltu@gmail.com>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

24
/** \file
25
  * This file contains the Media class implementation.
26
  * It contains the Media meta-datas, and information to be used with a VLC Media.
27 28 29
  * It's used by the Library
  */

30 31 32 33
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

34
#include <QUrl>
35
#include <QVariant>
36
#include <QFileInfo>
37

38
#include "Media.h"
39 40

#include "Clip.h"
luyikei's avatar
luyikei committed
41 42
#include "Main/Core.h"
#include "Library/Library.h"
43 44
#include "Tools/VlmcDebug.h"
#include "Project/Workspace.h"
45

46
const QString   Media::VideoExtensions = "*.avi *.3gp *.amv *.asf *.divx *.dv *.flv *.gxf "
47 48 49 50 51
                                         "*.iso *.m1v *.m2v *.m2t *.m2ts *.m4v *.mkv *.mov "
                                         "*.mp2 *.mp4 *.mpeg *.mpeg1 *.mpeg2 *.mpeg4 *.mpg "
                                         "*.mts *.mxf *.nsv *.nuv *.ogg *.ogm *.ogv *.ogx *.ps "
                                         "*.rec *.rm *.rmvb *.tod *.ts *.vob *.vro *.webm *.wmv";

52
const QString   Media::ImageExtensions = "*.png *.jpg *.jpeg";
53 54 55 56 57 58

const QString   Media::AudioExtensions = "*.a52 *.aac *.ac3 *.aiff *.amr *.aob *.ape "
                                         "*.dts *.flac *.it *.m4a *.m4p *.mid *.mka *.mlp "
                                         "*.mod *.mp1 *.mp2 *.mp3 *.mpc *.oga *.ogg *.oma "
                                         "*.rmi *.s3m *.spx *.tta *.voc *.vqf *.w64 *.wav "
                                         "*.wma *.wv *.xa *.xm";
59
const QString   Media::streamPrefix = "stream://";
60

61
Media::Media( medialibrary::MediaPtr media, const QUuid& uuid /* = QUuid() */ )
luyikei's avatar
luyikei committed
62
    : m_input( nullptr )
63
    , m_mlMedia( media )
64 65
    , m_baseClipUuid( uuid )
    , m_baseClip( nullptr )
66
{
67 68 69 70
    auto files = media->files();
    Q_ASSERT( files.size() > 0 );
    for ( const auto& f : files )
    {
71
        if ( f->type() == medialibrary::IFile::Type::Main )
72 73 74 75 76 77
        {
            m_mlFile = f;
            break;
        }
    }
    if ( m_mlFile == nullptr )
78
        vlmcFatal( "No file representing media %s", media->title().c_str(), "was found" );
79
    m_input.reset( new Backend::MLT::MLTInput( qPrintable( mrl() ) ) );
80 81
}

82 83
QString
Media::mrl() const
84
{
luyikei's avatar
luyikei committed
85
    return QUrl::fromPercentEncoding( QByteArray( m_mlFile->mrl().c_str() ) );
86 87
}

88 89
QString
Media::title() const
90
{
91
    return QUrl::fromPercentEncoding( QByteArray( m_mlMedia->title().c_str() ) );
92
}
93

94 95 96 97 98 99
qint64
Media::id() const
{
    return m_mlMedia->id();
}

100
QSharedPointer<Clip>
101 102 103
Media::baseClip()
{
    if ( m_baseClip == nullptr )
104
        m_baseClip.reset( new Clip( sharedFromThis(), 0, Backend::IInput::EndOfMedia, m_baseClipUuid ) );
105 106 107
    return m_baseClip;
}

108 109
QSharedPointer<Clip>
Media::cut( qint64 begin, qint64 end )
110
{
luyikei's avatar
luyikei committed
111
    auto clip = QSharedPointer<Clip>::create( sharedFromThis(), begin, end );
112 113 114 115 116 117 118 119 120 121 122
    m_clips[clip->uuid()] = clip;
    emit subclipAdded( clip );
    return clip;
}

void
Media::removeSubclip(const QUuid& uuid)
{
    if ( m_clips.remove( uuid ) == 0 )
        return;
    emit subclipRemoved( uuid );
123 124
}

luyikei's avatar
luyikei committed
125 126 127
QVariant
Media::toVariant() const
{
128 129 130 131 132 133 134 135 136 137 138 139
    QVariantHash h = {
        { "uuid", m_baseClip->uuid() },
        { "mlId", static_cast<qlonglong>( m_mlMedia->id() ) }
    };
    if ( m_clips.isEmpty() == false )
    {
        QVariantList l;
        for ( const auto& c : m_clips.values() )
            l << c->toVariant();
        h.insert( "clips", l );
    }
    return QVariant( h );
luyikei's avatar
luyikei committed
140 141
}

luyikei's avatar
luyikei committed
142 143
Backend::IInput*
Media::input()
144
{
luyikei's avatar
luyikei committed
145
    return m_input.get();
146 147
}

luyikei's avatar
luyikei committed
148 149
const Backend::IInput*
Media::input() const
150
{
luyikei's avatar
luyikei committed
151
    return m_input.get();
152 153
}

154 155 156 157 158 159 160 161 162 163 164 165
bool
Media::hasVideoTracks() const
{
    return input()->hasVideo();
}

bool
Media::hasAudioTracks() const
{
    return input()->hasAudio();
}

166 167
QSharedPointer<Media>
Media::fromVariant( const QVariant& v )
168
{
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    /**
     * The media is stored as such:
     * media: {
     *  mlId: <id>   // The media library ID
     *  uuid: <uuid> // The root clip UUID
     *  clips: [
     *    <clip 1>,  // The subclips
     *    ...
     *  ]
     * }
     */
    const auto& m = v.toMap();

    if ( m.contains( "mlId" ) == false || m.contains( "uuid" ) == false )
    {
        vlmcWarning() << "Invalid clip provided:" << m << "Missing 'mlId' and/or 'uuid' field(s)";
        return {};
    }
    auto mediaId = m["mlId"].toLongLong();
    auto uuid = m["uuid"].toUuid();
189
    auto mlMedia = Core::instance()->library()->mlMedia( mediaId );
190
    //FIXME: Is QSharedPointer exception safe in case its constructor throws an exception?
luyikei's avatar
luyikei committed
191
    auto media = QSharedPointer<Media>::create( mlMedia, uuid );
192 193 194 195 196 197 198 199 200 201 202

    // Now load the subclips:
    if ( m.contains( "clips" ) == false )
        return media;

    auto subclips = m["clips"].toList();
    for ( const auto& c : subclips )
    {
        media->loadSubclip( c.toMap() );
    }
    return media;
203
}
204

205
QString
206
Media::snapshot()
207
{
208
    return QString::fromStdString( m_mlMedia->thumbnail() );
209
}
210

211
QSharedPointer<Clip>
212 213
Media::loadSubclip( const QVariantMap& m )
{
214
    if ( m.contains( "libraryUuid" ) == false || m.contains( "begin" ) == false || m.contains( "end" ) == false )
215 216
    {
        vlmcWarning() << "Invalid clip provided:" << m;
217
        return {};
218
    }
219
    const auto& uuid = m["libraryUuid"].toUuid();
220 221
    const auto  begin = m["begin"].toLongLong();
    const auto  end = m["end"].toLongLong();
luyikei's avatar
luyikei committed
222
    auto clip = QSharedPointer<Clip>::create( sharedFromThis(), begin, end, uuid );
223 224 225 226 227

    m_clips[uuid] = clip;
    emit subclipAdded( clip );
    return clip;
}