예제 #1
0
        private void SeekInner(int frame)
        {
            int frame_block_number   = GetBlockNumber(frame);
            int current_block_number = GetBlockNumber(current_frame_);

            if (frame_block_number == current_block_number && current_frame_ <= frame) // シークする必要なし
            {
                return;
            }

            if (frame_block_number > 0)
            {
                long dts = key_dts_list_[frame_block_number - 1];
                AVCodecAPI.av_seek_frame(p_avformat_context, video_stream_index, dts + 1, 0);
                current_frame_ = DtsToVideoFrame(key_dts_list_[frame_block_number]);
            }
            else
            {
                AVCodecAPI.av_seek_frame(p_avformat_context, video_stream_index, 0, 0);
                current_frame_ = 0;
            }
            av_packet_queue_.Clear();   // パケットをフラッシュする

            audio_priority_times_ = 10; // シークした直後は音声優先
        }
예제 #2
0
        private void DecodeVideo(AVPacket packet)
        {
            int frame_finished;

            AVCodecAPI.avcodec_decode_video(video_stream.codec, p_frame, out frame_finished, packet.data, packet.size);

            if (frame_finished > 0)
            {
                BufferContainer buffer    = video_buffer_manager_.GetEmptyBufferContainer(current_frame_);
                double          dummy_val = 0;

                AVCodecAPI.avpicture_fill(p_frame_rgb, buffer.Buffer, (int)AVCodecAPI.AVPixelFormat.PIX_FMT_BGR24,
                                          Width, Height);

                IntPtr sws_context = AVCodecAPI.sws_getContext(video_codec_context.width, video_codec_context.height,
                                                               video_codec_context.pix_fmt, Width, Height,
                                                               (int)AVCodecAPI.AVPixelFormat.PIX_FMT_BGR24, 4, IntPtr.Zero, IntPtr.Zero, ref dummy_val);
                try
                {
                    AVCodecAPI.sws_scale(sws_context, p_frame, new IntPtr(p_frame.ToInt32() + 16), 0,
                                         video_codec_context.height, p_frame_rgb, new IntPtr(p_frame_rgb.ToInt32() + 16));
                }
                finally
                {
                    AVCodecAPI.sws_freeContext(sws_context);
                }
                buffer.Time    = (int)packet.dts;
                current_frame_ = DtsToVideoFrame((int)packet.dts);
                buffer.Frame   = current_frame_;
                video_buffer_manager_.SetBufferContainer(buffer);
            }
        }
예제 #3
0
        // H.264 動画で TimeScale が4倍精度になってるか調べる
        public bool IsTimeScaleFour()
        {
            int c;
            int count = 0;

            long[] dts = new long[4];

            if (video_codec_context.codec_id != 28) // H.264 でないので関係ない
            {
                return(false);
            }

            while ((c = AVCodecAPI.av_read_frame(p_avformat_context, p_packet)) >= 0)
            {
                PacketContainer container = new PacketContainer(p_packet);
                if (container.packet.stream_index == video_stream_index)
                {
                    dts[count] = container.packet.dts;
                    ++count;
                }
                container.Destruct();
                if (count >= dts.Length)
                {
                    break;
                }
            }
            AVCodecAPI.av_seek_frame(p_avformat_context, video_stream_index, 0, 0);

            return(dts[1] - dts[0] == 1001 && dts[2] - dts[1] == 1001 && dts[3] - dts[2] == 2002);
        }
예제 #4
0
        /// <summary>
        /// ファイルを閉じる
        /// </summary>
        public void Close()
        {
            if (IsOpen)
            {
                lock (command_queue_)
                {
                    command_queue_.Add(new Command(Command.Kind.EndThread));
                }
                thread_end_event_.WaitOne();

                if (video_stream_index >= 0)
                {
                    AVCodecAPI.avcodec_close(video_stream.codec);
                }
                if (audio_stream_index >= 0)
                {
                    AVCodecAPI.avcodec_close(audio_stream.codec);
                }
                AVCodecAPI.av_close_input_file(p_avformat_context);

                if (HasVideo)
                {
                    video_buffer_manager_.Close();
                }
                if (HasAudio)
                {
                    audio_buffer_manager_.Close();
                }

                Clear();
            }
        }
예제 #5
0
 public void Destruct()
 {
     if (ptr != IntPtr.Zero && packet.destruct != IntPtr.Zero)
     {
         AVCodecAPI.av_destruct_packet(ptr);
         packet = null;
         ptr    = IntPtr.Zero;
     }
 }
예제 #6
0
        private PacketContainer ReadPacket()
        {
            if (audio_priority_times_ > 0)
            {
                --audio_priority_times_;

                int c;
                while ((c = AVCodecAPI.av_read_frame(p_avformat_context, p_packet)) >= 0)
                {
                    PacketContainer packet = new PacketContainer(p_packet);

                    if (packet.packet.stream_index == audio_stream_index)
                    {
                        return(packet);
                    }
                    else
                    {
                        av_packet_queue_.Enqueue(packet);
                    }
                }
                if (av_packet_queue_.Count > 0)
                {
                    return(av_packet_queue_.Dequeue());
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                if (av_packet_queue_.Count > 0)
                {
                    return(av_packet_queue_.Dequeue());
                }
                else
                {
                    int c = AVCodecAPI.av_read_frame(p_avformat_context, p_packet);
                    if (c >= 0)
                    {
                        PacketContainer packet = new PacketContainer(p_packet);
                        return(packet);
                    }
                    else
                    {
                        return(null);
                    }
                }
            }
        }
예제 #7
0
        public void FixIllegalFrameRate()
        {
            int c;
            int count = 0;

            long[] dts = new long[50];

            while ((c = AVCodecAPI.av_read_frame(p_avformat_context, p_packet)) >= 0)
            {
                PacketContainer container = new PacketContainer(p_packet);
                if (container.packet.stream_index == video_stream_index)
                {
                    dts[count] = container.packet.dts;
                    ++count;
                }
                container.Destruct();
                if (count >= dts.Length)
                {
                    break;
                }
            }
            double average_dts = 0.0;

            for (int i = 5; i < count - 1; ++i) // 最初の5フレームは捨てる
            {
                average_dts += dts[i + 1] - dts[i];
            }
            average_dts /= (double)(count - 1 - 5);

            if (average_dts > 0)
            {
                double new_frame_rate_d = (double)video_stream.time_base.den / video_stream.time_base.num / average_dts;
                int    new_frame_rate   = (int)(new_frame_rate_d * 1000);
                int    new_frame_scale  = 1000;

                new_frame_rate  = 30;
                new_frame_scale = 1;

                for (int i = 0; i < key_frame_list_.Count; ++i)
                {
                    key_frame_list_[i] = (int)((double)key_frame_list_[i] * new_frame_rate * video_scale_
                                               / ((double)new_frame_scale * video_rate_));
                }
                video_rate_  = new_frame_rate;
                video_scale_ = new_frame_scale;
            }

            AVCodecAPI.av_seek_frame(p_avformat_context, video_stream_index, 0, 0);
        }
예제 #8
0
        private void DecodeAudio(AVPacket packet)
        {
            int output_size = audio_temp_buffer_size_;
            int c           = AVCodecAPI.avcodec_decode_audio2(audio_stream.codec, p_audio_buffer,
                                                               ref output_size, packet.data, packet.size);

            if (c < 0 || c != packet.size)
            {
                throw new AVCodecException();
            }
            if (output_size > 0)
            {
                int audio_byte = DtsToAudioByte((int)packet.dts);
                // output_size 単位にまるめる
                audio_byte = ((audio_byte + output_size / 2) / output_size) * output_size;

                audio_buffer_manager_.SetAudioData(p_audio_buffer, output_size, audio_byte);
            }
        }
예제 #9
0
        private void OpenCodec(string filename)
        {
            AVCodecAPI.av_register_all();

            int error_code = AVCodecAPI.av_open_input_file(out p_avformat_context, filename, IntPtr.Zero, 0, IntPtr.Zero);

            if (error_code != 0)
            {
                throw new AVCodecCannotOpenFileException();
            }
            error_code = AVCodecAPI.av_find_stream_info(p_avformat_context);
            if (error_code < 0)
            {
                throw new AVCodecException();
            }
            format_context = (AVFormatContext)Marshal.PtrToStructure(p_avformat_context, typeof(AVFormatContext));

            for (int i = 0; i < format_context.nb_streams; ++i)
            {
                AVStream       stream             = (AVStream)Marshal.PtrToStructure(format_context.streams[i], typeof(AVStream));
                AVCodecContext temp_codec_context = (AVCodecContext)Marshal.PtrToStructure(stream.codec,
                                                                                           typeof(AVCodecContext));
                if (temp_codec_context.codec_type == 0)
                {
                    if (video_stream_index < 0)
                    {
                        video_stream_index  = i;
                        video_stream        = stream;
                        video_codec_context = temp_codec_context;
                    }
                }
                else if (temp_codec_context.codec_type == 1)
                {
                    if (audio_stream_index < 0)
                    {
                        audio_stream_index  = i;
                        audio_stream        = stream;
                        audio_codec_context = temp_codec_context;
                    }
                }
            }

            if (video_stream_index >= 0)
            {
                p_video_codec = AVCodecAPI.avcodec_find_decoder(video_codec_context.codec_id);

                error_code = AVCodecAPI.avcodec_open(video_stream.codec, p_video_codec);
                if (error_code < 0)
                {
                    throw new AVCodecException();
                }
            }

            if (audio_stream_index >= 0)
            {
                p_audio_codec = AVCodecAPI.avcodec_find_decoder(audio_codec_context.codec_id);

                error_code = AVCodecAPI.avcodec_open(audio_stream.codec, p_audio_codec);
                if (error_code < 0)
                {
                    throw new AVCodecException();
                }
            }
        }
예제 #10
0
        /// <summary>
        /// 動画ファイルを開く
        /// </summary>
        /// <param name="filename">ファイルパス</param>
        /// <param name="width">動画サイズを固定する場合の幅(負の値を指定した場合は元の動画サイズになる)</param>
        /// <param name="height">動画サイズを固定する場合の高さ(負の値を指定した場合は元の動画サイズになる)</param>
        /// <param name="memory_size">使用するメモリサイズ(MB)(負の値を指定した場合は自動設定)</param>
        public void Open(string filename, int video_width, int video_height, int memory_size)
        {
            OpenCodec(filename);

            fixed_video_width_  = video_width;
            fixed_video_height_ = video_height;

            video_rate_  = video_stream.r_frame_rate.num;
            video_scale_ = video_stream.r_frame_rate.den;

            p_frame     = AVCodecAPI.avcodec_alloc_frame();
            p_frame_rgb = AVCodecAPI.avcodec_alloc_frame();

            p_packet = AVCodecAPI.av_malloc(Marshal.SizeOf(new AVPacket()));

            long last_dts = 0;
            int  c        = 0;

            bool is_first    = true;
            int  start_frame = 0;

            while (c >= 0)
            {
                if (!is_first)
                {
                    AVCodecAPI.av_seek_frame(p_avformat_context, video_stream_index, last_dts + 1, 0);
                }

                while ((c = AVCodecAPI.av_read_frame(p_avformat_context, p_packet)) >= 0)
                {
                    PacketContainer container = new PacketContainer(p_packet);
                    if (container.packet.stream_index == video_stream_index)
                    {
                        last_dts = container.packet.dts;
                        key_dts_list_.Add(last_dts);
                        key_frame_list_.Add(DtsToVideoFrame(last_dts));
                        if (is_first)
                        {
                            is_first    = false;
                            start_frame = key_frame_list_[key_frame_list_.Count - 1];
                        }
                        break;
                    }
                    container.Destruct();
                }
            }
            AVCodecAPI.av_seek_frame(p_avformat_context, video_stream_index, 0, 0);

            if (IsTimeScaleFour())
            {
                video_scale_ *= 4;
                for (int i = 0; i < key_frame_list_.Count; ++i)
                {
                    key_frame_list_[i] /= 4;
                }
            }

            if (video_rate_ / video_scale_ > 60)
            {
                FixIllegalFrameRate();
            }

            if (HasVideo)
            {
                if (memory_size <= 0)
                {
                    memory_size = Math.Min(Math.Max(BufferContainer.GetMemorySize() / (1024 * 1024) - 500, 100), 500); // 最小100MB、最大500MB
                }
                video_buffer_manager_ = new VideoBufferManager(this, FrameLength, memory_size * 1024 * 1024 / VideoPictureBufferSize, start_frame);
            }
            if (HasAudio)
            {
                audio_buffer_manager_ = new AudioBufferManager();
                audio_buffer_manager_.SetDataLength(AudioSampleRate * AudioChannel
                                                    * AudioBytesPerSample * format_context.duration / 1000000);

                p_audio_buffer = Marshal.AllocHGlobal(audio_temp_buffer_size_);

                audio_priority_times_ = 10;
            }
            StartDecoding();
        }