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; // シークした直後は音声優先 }
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); } }
// 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); }
/// <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(); } }
public void Destruct() { if (ptr != IntPtr.Zero && packet.destruct != IntPtr.Zero) { AVCodecAPI.av_destruct_packet(ptr); packet = null; ptr = IntPtr.Zero; } }
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); } } } }
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); }
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); } }
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(); } } }
/// <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(); }