VLCPlaylistInfo.m 14.1 KB
Newer Older
Benjamin Pracht's avatar
Benjamin Pracht committed
1
/*****************************************************************************
2
 * VLCPlaylistInfo.m: MacOS X interface module
Benjamin Pracht's avatar
Benjamin Pracht committed
3
 *****************************************************************************
4
 * Copyright (C) 2002-2015 VLC authors and VideoLAN
5
 * $Id$
Benjamin Pracht's avatar
Benjamin Pracht committed
6
 *
7
 * Authors: Benjamin Pracht <bigben at videolan dot org>
8
 *          Felix Paul Kühne <fkuehne at videolan dot org>
Benjamin Pracht's avatar
Benjamin Pracht committed
9 10 11 12 13
 *
 * 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.
14
 *
Benjamin Pracht's avatar
Benjamin Pracht committed
15 16 17 18 19 20 21
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 ******************************************************************************/
Benjamin Pracht's avatar
Benjamin Pracht committed
24

25
#import "CompatibilityFixes.h"
26
#import "VLCMain.h"
27 28
#import "VLCPlaylistInfo.h"
#import "VLCPlaylist.h"
29
#import <vlc_url.h>
Benjamin Pracht's avatar
Benjamin Pracht committed
30

31
@interface VLCInfo () <NSOutlineViewDataSource>
32 33 34 35 36 37 38 39 40
{
    VLCInfoTreeItem *rootItem;

    input_item_t *p_item;

    BOOL b_stats;
}
@end

41 42
@implementation VLCInfo

43
- (id)init
44
{
45 46
    self = [super initWithWindowNibName:@"MediaInfo"];
    if (self) {
47

48
    }
49

50
    return self;
51 52
}

53
- (void)windowDidLoad
Benjamin Pracht's avatar
Benjamin Pracht committed
54
{
55 56
    [self.window setExcludedFromWindowsMenu: YES];
    [self.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
57

58
    [self.window setTitle: _NS("Media Information")];
Benjamin Pracht's avatar
Benjamin Pracht committed
59

60
    _outlineView.dataSource = self;
61

62 63 64 65 66 67 68 69 70
    [_uriLabel setStringValue: _NS("Location")];
    [_titleLabel setStringValue: _NS("Title")];
    [_authorLabel setStringValue: _NS("Artist")];
    [_saveMetaDataButton setStringValue: _NS("Save Metadata")];

    [[_tabView tabViewItemAtIndex: 0] setLabel: _NS("General")];
    [[_tabView tabViewItemAtIndex: 1] setLabel: _NS("Codec Details")];
    [[_tabView tabViewItemAtIndex: 2] setLabel: _NS("Statistics")];
    [_tabView selectTabViewItemAtIndex: 0];
71 72

    /* constants defined in vlc_meta.h */
73 74 75 76 77 78 79 80 81 82
    [_genreLabel setStringValue: _NS(VLC_META_GENRE)];
    [_copyrightLabel setStringValue: _NS(VLC_META_COPYRIGHT)];
    [_collectionLabel setStringValue: _NS(VLC_META_ALBUM)];
    [_seqNumLabel setStringValue: _NS(VLC_META_TRACK_NUMBER)];
    [_descriptionLabel setStringValue: _NS(VLC_META_DESCRIPTION)];
    [_dateLabel setStringValue: _NS(VLC_META_DATE)];
    [_languageLabel setStringValue: _NS(VLC_META_LANGUAGE)];
    [_nowPlayingLabel setStringValue: _NS(VLC_META_NOW_PLAYING)];
    [_publisherLabel setStringValue: _NS(VLC_META_PUBLISHER)];
    [_encodedbyLabel setStringValue: _NS(VLC_META_ENCODED_BY)];
83

84
    /* statistics */
85 86 87 88 89
    [_inputLabel setStringValue: _NS("Input")];
    [_readBytesLabel setStringValue: _NS("Read at media")];
    [_inputBitrateLabel setStringValue: _NS("Input bitrate")];
    [_demuxBytesLabel setStringValue: _NS("Demuxed")];
    [_demuxBitrateLabel setStringValue: _NS("Stream bitrate")];
90

91 92 93 94
    [_videoLabel setStringValue: _NS("Video")];
    [_videoDecodedLabel setStringValue: _NS("Decoded blocks")];
    [_displayedLabel setStringValue: _NS("Displayed frames")];
    [_lostFramesLabel setStringValue: _NS("Lost frames")];
95

96 97 98 99
    [_soutLabel setStringValue: _NS("Streaming")];
    [_sentPacketsLabel setStringValue: _NS("Sent packets")];
    [_sentBytesLabel setStringValue: _NS("Sent bytes")];
    [_sentBitrateLabel setStringValue: _NS("Send rate")];
100

101 102 103 104
    [_audioLabel setStringValue: _NS("Audio")];
    [_audioDecodedLabel setStringValue: _NS("Decoded blocks")];
    [_playedAudioBuffersLabel setStringValue: _NS("Played buffers")];
    [_lostAudioBuffersLabel setStringValue: _NS("Lost buffers")];
105

106
    [self.window setInitialFirstResponder: _uriLabel];
107

108
    b_stats = var_InheritBool(getIntf(), "stats");
109 110 111 112 113 114 115 116
    if (!b_stats) {
        if ([_tabView numberOfTabViewItems] > 2)
            [_tabView removeTabViewItem: [_tabView tabViewItemAtIndex: 2]];
    }
    else
        [self initMediaPanelStats];


117
    /* We may be awoken from nib way after initialisation
118
     *Update ourselves */
119 120 121
    [self updatePanelWithItem:p_item];
}

Benjamin Pracht's avatar
Benjamin Pracht committed
122

123 124
- (void)dealloc
{
125 126
    if (p_item)
        vlc_gc_decref(p_item);
127
}
Benjamin Pracht's avatar
Benjamin Pracht committed
128

129 130
- (void)updateCocoaWindowLevel:(NSInteger)i_level
{
131
    if (self.isWindowLoaded && [self.window isVisible] && [self.window level] != i_level)
132
        [self.window setLevel: i_level];
133 134
}

135
- (IBAction)toggleWindow:(id)sender
136
{
137 138 139 140 141 142
    if ([self.window isKeyWindow])
        [self.window orderOut:sender];
    else {
        [self.window setLevel: [[[VLCMain sharedInstance] voutController] currentStatusWindowLevel]];
        [self.window makeKeyAndOrderFront:sender];
    }
143 144
}

maxime Ripard's avatar
maxime Ripard committed
145 146 147
- (void)initMediaPanelStats
{
    //Initializing Input Variables
148 149 150 151
    [_readBytesTextField setStringValue: [NSString stringWithFormat:_NS("%.1f KiB"), (float)0]];
    [_inputBitrateTextField setStringValue: [NSString stringWithFormat:@"%6.0f kb/s", (float)0]];
    [_demuxBytesTextField setStringValue: [NSString stringWithFormat:_NS("%.1f KiB"), (float)0]];
    [_demuxBitrateTextField setStringValue: [NSString stringWithFormat:@"%6.0f kb/s", (float)0]];
152

maxime Ripard's avatar
maxime Ripard committed
153
    //Initializing Video Variables
154 155 156
    [_videoDecodedTextField setIntValue:0];
    [_displayedTextField setIntValue:0];
    [_lostFramesTextField setIntValue:0];
maxime Ripard's avatar
maxime Ripard committed
157 158

    //Initializing Output Variables
159 160 161
    [_sentPacketsTextField setIntValue: 0];
    [_sentBytesTextField setStringValue: [NSString stringWithFormat:_NS("%.1f KiB"), (float)0]];
    [_sentBitrateTextField setStringValue: [NSString stringWithFormat:@"%6.0f kb/s", (float)0]];
maxime Ripard's avatar
maxime Ripard committed
162 163

    //Initializing Audio Variables
164 165 166
    [_audioDecodedTextField setIntValue:0];
    [_playedAudioBuffersTextField setIntValue: 0];
    [_lostAudioBuffersTextField setIntValue: 0];
maxime Ripard's avatar
maxime Ripard committed
167 168
}

169 170 171 172 173 174 175 176
- (void)updateMetadata
{
    if (!p_item)
        return;

    [self updatePanelWithItem:p_item];
}

177
- (void)updatePanelWithItem:(input_item_t *)_p_item;
178
{
179 180 181 182 183 184 185 186
    if (_p_item != p_item) {
        if (p_item)
            vlc_gc_decref(p_item);
        [_saveMetaDataButton setEnabled: NO];
        if (_p_item)
            vlc_gc_incref(_p_item);
        p_item = _p_item;
    }
187

188 189 190
    if (!self.isWindowLoaded)
        return;

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    if (!p_item) {
        /* Erase */
#define SET( foo ) \
[_##foo##TextField setStringValue:@""];
        SET( uri );
        SET( title );
        SET( author );
        SET( collection );
        SET( seqNum );
        SET( genre );
        SET( copyright );
        SET( publisher );
        SET( nowPlaying );
        SET( language );
        SET( date );
        SET( description );
        SET( encodedby );
#undef SET
        [_imageWell setImage: [NSImage imageNamed: @"noart.png"]];
    } else {
        if (!input_item_IsPreparsed(p_item))
212
            libvlc_MetadataRequest(getIntf()->obj.libvlc, p_item, META_REQUEST_OPTION_NONE, -1, NULL);
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

        /* fill uri info */
        char *psz_url = vlc_uri_decode(input_item_GetURI(p_item));
        [_uriTextField setStringValue:toNSStr(psz_url)];
        free(psz_url);

        /* fill title info */
        char *psz_title = input_item_GetTitle(p_item);
        if (!psz_title)
            psz_title = input_item_GetName(p_item);
        [_titleTextField setStringValue:toNSStr(psz_title)];
        free(psz_title);

#define SET( foo, bar ) \
char *psz_##foo = input_item_Get##bar ( p_item ); \
[_##foo##TextField setStringValue:toNSStr(psz_##foo)]; \
FREENULL( psz_##foo );

        /* fill the other fields */
        SET( author, Artist );
        SET( collection, Album );
        SET( seqNum, TrackNum );
        SET( genre, Genre );
        SET( copyright, Copyright );
        SET( publisher, Publisher );
        SET( nowPlaying, NowPlaying );
        SET( language, Language );
        SET( date, Date );
        SET( description, Description );
        SET( encodedby, EncodedBy );

#undef SET

        char *psz_meta;
        NSImage *image;
        psz_meta = input_item_GetArtURL(p_item);

        /* FIXME Can also be attachment:// */
        if (psz_meta && strncmp(psz_meta, "attachment://", 13))
            image = [[NSImage alloc] initWithContentsOfURL: [NSURL URLWithString:toNSStr(psz_meta)]];
        else
            image = [NSImage imageNamed: @"noart.png"];
        [_imageWell setImage: image];
        FREENULL(psz_meta);
    }
258

259 260
    /* reload the codec details table */
    [self updateStreamsList];
261

262 263
    /* update the stats once to display p_item change faster */
    [self updateStatistics];
Benjamin Pracht's avatar
Benjamin Pracht committed
264 265
}

266
- (void)updateStatistics
267
{
268
    if (!self.isWindowLoaded || !b_stats)
269 270
        return;

271 272 273
    if (!p_item || !p_item->p_stats) {
        [self initMediaPanelStats];
        return;
274
    }
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

    if (![self.window isVisible])
        return;

    vlc_mutex_lock(&p_item->p_stats->lock);

    /* input */
    [_readBytesTextField setStringValue: [NSString stringWithFormat:
                                          @"%8.0f KiB", (float)(p_item->p_stats->i_read_bytes)/1024]];
    [_inputBitrateTextField setStringValue: [NSString stringWithFormat:
                                             @"%6.0f kb/s", (float)(p_item->p_stats->f_input_bitrate)*8000]];
    [_demuxBytesTextField setStringValue: [NSString stringWithFormat:
                                           @"%8.0f KiB", (float)(p_item->p_stats->i_demux_read_bytes)/1024]];
    [_demuxBitrateTextField setStringValue: [NSString stringWithFormat:
                                             @"%6.0f kb/s", (float)(p_item->p_stats->f_demux_bitrate)*8000]];

    /* Video */
    [_videoDecodedTextField setIntValue: p_item->p_stats->i_decoded_video];
    [_displayedTextField setIntValue: p_item->p_stats->i_displayed_pictures];
    [_lostFramesTextField setIntValue: p_item->p_stats->i_lost_pictures];

    /* Sout */
    [_sentPacketsTextField setIntValue: p_item->p_stats->i_sent_packets];
    [_sentBytesTextField setStringValue: [NSString stringWithFormat: @"%8.0f KiB",
                                          (float)(p_item->p_stats->i_sent_bytes)/1024]];
    [_sentBitrateTextField setStringValue: [NSString stringWithFormat:
                                            @"%6.0f kb/s", (float)(p_item->p_stats->f_send_bitrate*8)*1000]];

    /* Audio */
    [_audioDecodedTextField setIntValue: p_item->p_stats->i_decoded_audio];
    [_playedAudioBuffersTextField setIntValue: p_item->p_stats->i_played_abuffers];
    [_lostAudioBuffersTextField setIntValue: p_item->p_stats->i_lost_abuffers];

    vlc_mutex_unlock(&p_item->p_stats->lock);
309 310
}

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
- (void)updateStreamsList
{
    rootItem = [[VLCInfoTreeItem alloc] init];

    if (p_item) {
        vlc_mutex_lock(&p_item->lock);
        // build list of streams
        NSMutableArray *streams = [NSMutableArray array];

        for (int i = 0; i < p_item->i_categories; i++) {
            info_category_t *cat = p_item->pp_categories[i];

            VLCInfoTreeItem *subItem = [[VLCInfoTreeItem alloc] init];
            subItem.name = toNSStr(cat->psz_name);

            // Build list of codec details
            NSMutableArray *infos = [NSMutableArray array];

            for (int j = 0; j < cat->i_infos; j++) {
                VLCInfoTreeItem *infoItem = [[VLCInfoTreeItem alloc] init];
                infoItem.name = toNSStr(cat->pp_infos[j]->psz_name);
                infoItem.value = toNSStr(cat->pp_infos[j]->psz_value);
                [infos addObject:infoItem];
            }

            subItem.children = [infos copy];
            [streams addObject:subItem];
        }

        rootItem.children = [streams copy];
        vlc_mutex_unlock(&p_item->lock);
    }

    [_outlineView reloadData];
    [_outlineView expandItem:nil expandChildren:YES];
}

348 349
- (IBAction)metaFieldChanged:(id)sender
{
350
    [_saveMetaDataButton setEnabled: YES];
351 352
}

353
- (IBAction)saveMetaData:(id)sender
Benjamin Pracht's avatar
Benjamin Pracht committed
354
{
355 356 357 358 359 360 361
    if (!p_item) {
        NSAlert *alert = [[NSAlert alloc] init];
        [alert setMessageText:_NS("Error while saving meta")];
        [alert setInformativeText:_NS("VLC was unable to save the meta data.")];
        [alert addButtonWithTitle:_NS("OK")];
        [alert runModal];
    }
362

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    #define utf8( _blub ) \
        [[_blub stringValue] UTF8String]

    input_item_SetName( p_item, utf8( _titleTextField ) );
    input_item_SetTitle( p_item, utf8( _titleTextField ) );
    input_item_SetArtist( p_item, utf8( _authorTextField ) );
    input_item_SetAlbum( p_item, utf8( _collectionTextField ) );
    input_item_SetGenre( p_item, utf8( _genreTextField ) );
    input_item_SetTrackNum( p_item, utf8( _seqNumTextField ) );
    input_item_SetDate( p_item, utf8( _dateTextField ) );
    input_item_SetCopyright( p_item, utf8( _copyrightTextField ) );
    input_item_SetPublisher( p_item, utf8( _publisherTextField ) );
    input_item_SetDescription( p_item, utf8( _descriptionTextField ) );
    input_item_SetLanguage( p_item, utf8( _languageTextField ) );

378
    playlist_t *p_playlist = pl_Get(getIntf());
379
    input_item_WriteMeta(VLC_OBJECT(p_playlist), p_item);
380

381
    var_SetBool(p_playlist, "intf-change", true);
382 383
    [self updatePanelWithItem: p_item];

384
    [_saveMetaDataButton setEnabled: NO];
385 386
}

387 388
- (IBAction)downloadCoverArt:(id)sender
{
389
    playlist_t *p_playlist = pl_Get(getIntf());
390
    if (p_item) libvlc_ArtRequest(getIntf()->obj.libvlc, p_item, META_REQUEST_OPTION_NONE);
391 392
}

393 394
@end

Benjamin Pracht's avatar
Benjamin Pracht committed
395

396
@implementation VLCInfo (NSTableDataSource)
397

398
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
399
{
400
    return (item == nil) ? [rootItem children].count : [item children].count;
401 402 403
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
404
    return ([item children].count > 0);
405 406
}

407
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
408
{
409
    return (item == nil) ? [[rootItem children] objectAtIndex:index] : [[item children]objectAtIndex:index];
410 411 412 413
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
414 415 416
    if (!item)
        return @"";

417
    if ([[tableColumn identifier] isEqualToString:@"0"])
418
        return [item name];
419
    else
420
        return [item value];
421 422 423 424
}

@end

425 426

@implementation VLCInfoTreeItem
427

Benjamin Pracht's avatar
Benjamin Pracht committed
428
@end