假设有一个解码帧序列为IBP,当解码器对其解码时,解码第一帧肯定是序列中的第一帧 I, 但我们思考一下第二帧,已知 B 帧的解码需要参考前一个 I 帧或 P 帧以及后面一个 P 帧,那么解码的第二帧显然不能是序列中的第二帧 B 帧,而是第三帧 P 帧,因此我们得到了下面的一个 PTS 和 DTS 关系
A parent-Coroutine finishes only after all its child-Coroutines have finished.
When a parent-Coroutine or scope finishes abnormally, either through cancelation or through an exception, all its child-Coroutines, that are still active, are canceled and new child-Coroutines can no longer be launched.
When a child-Coroutine finishes abnormally, its parent-Coroutine or scope finishes abnormally.
A parent-Coroutine finishes only after all its child-Coroutines have finished.
When a parent-Coroutine or scope finishes abnormally, either through cancelation or through an exception, all its child-Coroutines, that are still active, are canceled and new child-Coroutines can no longer be launched.
When a child-Coroutine finishes abnormally, its parent-Coroutine or scope (a) finishes abnormally if the parent is not a supervisor or (b) keeps running if the parent is a supervisor.
// Record result int result; // R1 Java String -> C String constchar *path = env->GetStringUTFChars(path_, 0); // Register FFmpeg components av_register_all(); // R2 initializes the AVFormatContext context AVFormatContext *format_context = avformat_alloc_context(); // Open Video File result = avformat_open_input(&format_context, path, NULL, NULL); if (result < 0) { LOGE("Player Error : Can not open video file"); return; } // Finding Stream Information of Video Files result = avformat_find_stream_info(format_context, NULL); if (result < 0) { LOGE("Player Error : Can not find video file stream info"); return; } // Find Video Encoder int video_stream_index = -1; for (int i = 0; i < format_context->nb_streams; i++) { // Matching Video Stream if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; } } // No video stream found if (video_stream_index == -1) { LOGE("Player Error : Can not find video stream"); return; } // Initialization of Video Encoder Context AVCodecContext *video_codec_context = avcodec_alloc_context3(NULL); avcodec_parameters_to_context(video_codec_context, format_context->streams[video_stream_index]->codecpar); // Initialization of Video Encoder AVCodec *video_codec = avcodec_find_decoder(video_codec_context->codec_id); if (video_codec == NULL) { LOGE("Player Error : Can not find video codec"); return; } // R3 Opens Video Decoder result = avcodec_open2(video_codec_context, video_codec, NULL); if (result < 0) { LOGE("Player Error : Can not find video stream"); return; } // Getting the Width and Height of Video int videoWidth = video_codec_context->width; int videoHeight = video_codec_context->height;
// R4 Initializes Native Window s for Playing Videos ANativeWindow *native_window = ANativeWindow_fromSurface(env, surface); // surface对应java层的surface对象 if (native_window == NULL) { LOGE("Player Error : Can not create native window"); return; } // Limit the number of pixels in the buffer by setting the width, not the physical display size of the screen. // If the buffer does not match the display size of the physical screen, the actual display may be stretched or compressed images. result = ANativeWindow_setBuffersGeometry(native_window, videoWidth, videoHeight,WINDOW_FORMAT_RGBA_8888); if (result < 0){ LOGE("Player Error : Can not set native window buffer"); ANativeWindow_release(native_window); return; } // Define drawing buffer ANativeWindow_Buffer window_buffer; // There are three declarative data containers // Data container Packet encoding data before R5 decoding AVPacket *packet = av_packet_alloc(); av_init_packet(packet); // Frame Pixel Data of Data Container After R6 Decoding Can't Play Pixel Data Directly and Need Conversion AVFrame *frame = av_frame_alloc(); // R7 converted data container where the data can be used for playback AVFrame *rgba_frame = av_frame_alloc(); // Data format conversion preparation // Output Buffer int buffer_size = av_image_get_buffer_size(AV_PIX_FMT_RGBA, videoWidth, videoHeight, 1); // R8 Application for Buffer Memory uint8_t *out_buffer = (uint8_t *) av_malloc(buffer_size * sizeof(uint8_t)); LOGI("outBuffer size: %d, videoWidth: %d, videoHeight: %d, pix_fmt: %d", buffer_size * sizeof(uint8_t), videoWidth, videoHeight, video_codec_context->pix_fmt); av_image_fill_arrays(rgba_frame->data, rgba_frame->linesize, out_buffer, AV_PIX_FMT_RGBA, videoWidth, videoHeight, 1); // R9 Data Format Conversion Context structSwsContext *data_convert_context = sws_getContext( videoWidth, videoHeight, video_codec_context->pix_fmt, videoWidth, videoHeight, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); // Start reading frames
AVFormatContext *avFormatContext = nullptr; LOGI("video_config_create, open file uri: %s", uri); if (avformat_open_input(&avFormatContext, uri, nullptr, nullptr)) { // open IO, 如果成功, avFormatContext将有值 returnnullptr; }
if (avformat_find_stream_info(avFormatContext, nullptr) < 0) { avformat_free_context(avFormatContext); returnnullptr; };
for (int pos = 0; pos < avFormatContext->nb_streams; pos++) { // Getting the name of a codec of the very first video stream AVCodecParameters *parameters = avFormatContext->streams[pos]->codecpar; if (parameters->codec_type == AVMEDIA_TYPE_VIDEO) { videoConfig->parameters = parameters; videoConfig->avVideoCodec = avcodec_find_decoder(parameters->codec_id); videoConfig->videoStreamIndex = pos; break; } }
bool MMKV::ensureMemorySize(size_t newSize) { if (!isFileValid()) { MMKVWarning("[%s] file not valid", m_mmapID.c_str()); returnfalse; }
// make some room for placeholder constexprsize_t ItemSizeHolderSize = 4; if (m_dic.empty()) { newSize += ItemSizeHolderSize; } if (newSize >= m_output->spaceLeft() || m_dic.empty()) { // 空间不够,进行一次全量写入,这次全量写入会把过长的冗余字段全部覆盖写 // try a full rewrite to make space auto fileSize = m_file->getFileSize(); MMBuffer data = MiniPBCoder::encodeDataWithObject(m_dic); size_t lenNeeded = data.length() + Fixed32Size + newSize; size_t avgItemSize = lenNeeded / std::max<size_t>(1, m_dic.size()); size_t futureUsage = avgItemSize * std::max<size_t>(8, (m_dic.size() + 1) / 2); // 1. no space for a full rewrite, double it // 2. or space is not large enough for future usage, double it to avoid frequently full rewrite if (lenNeeded >= fileSize || (lenNeeded + futureUsage) >= fileSize) { size_t oldSize = fileSize; do { fileSize *= 2; // 2倍的扩充策略 } while (lenNeeded + futureUsage >= fileSize); MMKVInfo("extending [%s] file size from %zu to %zu, incoming size:%zu, future usage:%zu", m_mmapID.c_str(), oldSize, fileSize, newSize, futureUsage);
// if we can't extend size, rollback to old state if (!m_file->truncate(fileSize)) { returnfalse; }
// check if we fail to make more space if (!isFileValid()) { MMKVWarning("[%s] file not valid", m_mmapID.c_str()); returnfalse; } } return doFullWriteBack(std::move(data)); // 全量写入 } returntrue; }