public BufferContainer GetEmptyBufferContainer(int frame) { if (current_using_frame_num_ < buffering_frame_limit_) { BufferContainer buffer = null; try { buffer = new BufferContainer(parent_.VideoPictureBufferSize); } catch (OutOfMemoryException) { buffering_frame_limit_ = current_using_frame_num_; // ここで打ち止め } if (buffer != null) { ++current_using_frame_num_; return(buffer); } } if (empty_buffer_stack_.Count > 0) { return(empty_buffer_stack_.Pop()); } else { int empty_index = GetEmptyIndex(frame); BufferContainer buffer = video_buffer_list_[empty_index]; video_buffer_list_[empty_index] = null; return(buffer); } }
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); } }
public void SetBufferContainer(BufferContainer buffer) { if (buffer.Frame < 0 || buffer.Frame >= parent_.FrameLength) { empty_buffer_stack_.Push(buffer); } else if (video_buffer_list_[buffer.Frame] != null) { empty_buffer_stack_.Push(buffer); } else { video_buffer_list_[buffer.Frame] = buffer; } }
/// <summary> /// フレームを取得する。デコードがまだされていない場合は null が返ると同時に /// デコードスレッドに指定したフレーム番号をデコードするように要求する /// </summary> /// <param name="frame">フレーム番号</param> /// <returns></returns> public BufferContainer GetFrame(int frame) { if (frame < 0) { frame = 0; } else if (frame >= FrameLength) { frame = FrameLength - 1; } BufferContainer buffer = video_buffer_manager_.GetFrame(frame); if (buffer == null) { RequireSeeking(frame); } return(buffer); }
/// <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(); }