// 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); }
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); }
/// <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(); }