public override void readMetadata(MediaProbe mediaProbe, Stream data, MetadataFactory.ReadOptions options, BaseMetadata media,
            CancellationToken token, int timeoutSeconds)
        {
            AudioMetadata audio = media as AudioMetadata;
                                       
            audio.DurationSeconds = mediaProbe.DurationSeconds;
            audio.SizeBytes = mediaProbe.SizeBytes;

            audio.AudioContainer = mediaProbe.Container;                     
            audio.AudioCodec = mediaProbe.AudioCodecName;
            audio.SamplesPerSecond = mediaProbe.SamplesPerSecond;
            audio.BitsPerSample = (short)(mediaProbe.BytesPerSample * 8);
            audio.NrChannels = (short)mediaProbe.NrChannels;

            audio.BitRate = mediaProbe.AudioBitRate == 0 ? (long?)null : mediaProbe.AudioBitRate;             
       
            List<string> fsMetaData = mediaProbe.MetaData;
               
            try
            {                
                if (options.HasFlag(MetadataFactory.ReadOptions.GENERATE_THUMBNAIL))
                {
                    generateThumbnail(mediaProbe, audio, token, timeoutSeconds, 1);
                }                                        
            }
            catch (Exception e)
            {
                Logger.Log.Error("Cannot read audio thumbnail: " + audio.Location, e);
                media.MetadataReadError = e;
            }

            if(audio.AudioCodec.ToLower().Equals("mp3") || audio.AudioCodec.ToLower().StartsWith("pcm"))
            {
                audio.SupportsXMPMetadata = true;                
            }
            else
            {
                audio.SupportsXMPMetadata = false;
            }

            base.readMetadata(mediaProbe, data, options, media, token, timeoutSeconds);
 
            parseFFMpegMetaData(fsMetaData, audio);
                      
        }
        public override void readMetadata(MediaProbe mediaProbe, Stream data, MetadataFactory.ReadOptions options, BaseMetadata media,
            CancellationToken token, int timeoutSeconds)
        {
            ImageMetadata image = media as ImageMetadata;
            image.SizeBytes = data.Length;

            if (FileUtils.isUrl(image.Location))
            {
                image.SupportsXMPMetadata = false;
            }
            else
            {
                image.SupportsXMPMetadata = true;
                base.readMetadata(mediaProbe, data, options, media, token, timeoutSeconds);
            }

            image.ImageContainer = mediaProbe.Container;
            image.Width = mediaProbe.Width;
            image.Height = mediaProbe.Height;
            image.PixelFormat = mediaProbe.PixelFormat;
            image.BitsPerPixel = (short)mediaProbe.BitsPerPixel;
           
            List<String> fsMetaData = mediaProbe.MetaData;
               
            try
            {                   
                if (options.HasFlag(MetadataFactory.ReadOptions.GENERATE_THUMBNAIL))
                {
                    generateThumbnail(mediaProbe, image, token, timeoutSeconds, 1);
                }
                    
            }
            catch (Exception e)
            {
                Logger.Log.Error("Cannot create image thumbnail: " + image.Location, e);
                media.MetadataReadError = e;
            }
            
                        
        }
        public override void readMetadata(MediaProbe mediaProbe, Stream data, MetadataFactory.ReadOptions options, BaseMetadata media,
            CancellationToken token, int timeoutSeconds)
        {
            VideoMetadata video = media as VideoMetadata;

            video.DurationSeconds = mediaProbe.DurationSeconds;
            video.SizeBytes = mediaProbe.SizeBytes;

            video.Width = mediaProbe.Width;
            video.Height = mediaProbe.Height;

            video.VideoContainer = mediaProbe.Container;
            video.VideoCodec = mediaProbe.VideoCodecName;

            video.PixelFormat = mediaProbe.PixelFormat;
            video.BitsPerPixel = (short)mediaProbe.BitsPerPixel;

            video.FramesPerSecond = mediaProbe.FrameRate;

            video.VideoBitRate = mediaProbe.VideoBitRate == 0 ? (long?)null : mediaProbe.VideoBitRate;
            video.AudioBitRate = mediaProbe.AudioBitRate == 0 ? (long?)null : mediaProbe.AudioBitRate;
           
            if (!String.IsNullOrEmpty(mediaProbe.AudioCodecName))
            {
                video.AudioCodec = mediaProbe.AudioCodecName;
                video.SamplesPerSecond = mediaProbe.SamplesPerSecond;
                video.BitsPerSample = (short)(mediaProbe.BytesPerSample * 8);
                video.NrChannels = (short)mediaProbe.NrChannels;
            }
            else
            {
                video.AudioCodec = null;
                video.SamplesPerSecond = null;
                video.BitsPerSample = null;
                video.NrChannels = null;
            }

            List<String> fsMetaData = mediaProbe.MetaData;

            try
            {
                if (options.HasFlag(MetadataFactory.ReadOptions.GENERATE_THUMBNAIL))
                {
                    generateThumbnail(mediaProbe, video, token, timeoutSeconds, 1);
                }
               
            }
            catch (Exception e)
            {
                Logger.Log.Error("Cannot create video thumbnail: " + video.Location, e);
                media.MetadataReadError = e;
            }

            if (fsMetaData != null)
            {
                video.SupportsXMPMetadata = supportsXMPMetadata(video, fsMetaData);
            }
            else
            {
                video.SupportsXMPMetadata = false;
            }

            base.readMetadata(mediaProbe, data, options, media, token, timeoutSeconds);

            parseFFMpegMetaData(fsMetaData, video);


        }
        public static BaseMetadata read(String location, MetadataFactory.ReadOptions options, CancellationToken token, int timeoutSeconds)
        {
            BaseMetadata metadata = new UnknownMetadata(FileUtils.getPathWithoutFileName(location));
            metadata.Name = Path.GetFileName(location);

            Logger.Log.Info("Reading metadata for: " + location);

            int timeoutMs = timeoutSeconds * 1000;

            Stream data = FileUtils.waitForFileAccess(location, FileAccess.Read, timeoutMs, token);

            MediaProbe mediaProbe = new MediaProbe();

            try
            {
                mediaProbe.open(location, token);

                switch (mediaProbe.MediaType)
                {
                    case MediaType.AUDIO_MEDIA:
                        {
                            metadata = new AudioMetadata(location, data);                          
                            AudioFileMetadataReader reader = new AudioFileMetadataReader();
                            reader.readMetadata(mediaProbe, data, options, metadata, token, timeoutSeconds);
                            break;
                        }
                    case MediaType.IMAGE_MEDIA:
                        {
                            metadata = new ImageMetadata(location, data);                        
                            ImageFileMetadataReader reader = new ImageFileMetadataReader();
                            reader.readMetadata(mediaProbe, data, options, metadata, token, timeoutSeconds);
                            break;
                        }                
                    case MediaType.VIDEO_MEDIA:
                        {
                            metadata = new VideoMetadata(location, data);                       
                            VideoFileMetadataReader reader = new VideoFileMetadataReader();
                            reader.readMetadata(mediaProbe, data, options, metadata, token, timeoutSeconds);
                            break;
                        }
                    default:
                        break;
                }                

                FileInfo info = new FileInfo(location);
                info.Refresh();

                if (info.Attributes.HasFlag(FileAttributes.ReadOnly))
                {
                    metadata.IsReadOnly = true;
                }

                if (!options.HasFlag(MetadataFactory.ReadOptions.LEAVE_STREAM_OPENED_AFTER_READ))
                {
                    metadata.close();
                }

            }
            catch (Exception e)
            {
                metadata.MetadataReadError = e;                
            }
            finally
            {                
                mediaProbe.close();
                mediaProbe.Dispose();                
            }
                        
            return metadata;
        }