C++调用ffmpeg解复用、解码案例

ffmpeg 接收网络流并解码_FFmpeg编程入门系列(1) FFmpeg播放器框架一个完整的播放器框架如下:媒体文件可以是本地文件,也可以是网络流;解复用器主要是分离出音视频包。音视频packet队列:这个是分开设计。为了匹配解复用器之间的速度以及防止网络抖动。音视频解码:主要是把packet数据变为frame。音视频frame队列:主要是为了匹配解码和音视频后期处理,播放的速度及防止网络抖动,带来不好的体验,比如卡顿等。扬声器与显示器:分别是播放声音和渲... 阅读详情

框架

        一个封装文件(mp4)如何播放?大体流程如下:

 案例

        本案例实现在windows环境下,调用ffmpeg4.4.5动态库实现上述从解封装、视频解码、音频解码的全部过程,案例测试通过。由于ffmpeg接口功能网上资料较多,这里就不在赘述,代码如下:

 1、DeCoder.h

#pragma once
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}

#include <iostream>
#include <fstream>
#include <vector>


#define ADTS_HERDER_LEN 7

const int sampling_frequencies[] = {
    96000, //0x0
    88200, //0x1
    64000, //0x2
    48000, //0x3
    44100, //0x4
    32000, //0x5
    24000, //0x6
    22050, //0x7
    16000, //0x8
    12000, //0x9
    11025, //0xa
    8000   //0xb  // 0xc d e f是保留的
};

int test_deMuxer();

int test_deCoderH264();
int test_deCoderAac();

2、DeMuxer.cpp


#include "DeCoder.h"

using namespace std;

int adts_header(uint8_t* const p_adts_header, const int data_length, const int profile, const int samplerate, const int channels)
{
    int sampling_frequency_index = 3; //48000
    int adtsLen = data_length + ADTS_HERDER_LEN;   // ADTS的头部信息总是占7个字节

    int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]); //求内存的分配大小
    int i = 0;
    for (i = 0; i < frequencies_size; i++)
    {
        if (sampling_frequencies[i] == samplerate)
        {
            sampling_frequency_index = i;
            break;
        }
    }
    if (i > frequencies_size)
    {
        printf("unsupport samplerate:%d \n", samplerate);
        return -1;
    }

    p_adts_header[0] = 0xff;        //syncword:0xfff    高8bits  1111 1111  位数不足则用0补齐
    p_adts_header[1] = 0xf0;        //syncword:0xfff    低4bits  前面的4bit是属于syncword,后面的才是重新赋值    1111 0000
    p_adts_header[1] |= (0 << 3);   //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit  |= 按位或后赋值 1111 0000  和 0000  = 1111 0000
    p_adts_header[1] |= (0 << 1);                                       //Layer:0                                 2bits                       1111 0000 和 00
    p_adts_header[1] |= 1;                                              // protection absent:1   不校验                 1bit                      1111 00000 和 1  = 1111 0000   0000 0001=  1111 0001

    p_adts_header[2] = (profile << 6);                                   //profile:profile               2bits                    profile :1110 0011  左移6位 1100 0000
    p_adts_header[2] |= (sampling_frequency_index & 0x0f) << 2;           //sampling frequency index:sampling_frequency_index  4bits
    p_adts_header[2] |= (0 << 1);                                        //private bit:0                   1bit
    p_adts_header[2] |= (channels & 0x04) >> 2;                          //channel configuration:channels  高1bit

    p_adts_header[3] = (channels & 0x03) << 6;                          //channel configuration:channels 低2bits
    p_adts_header[3] |= (0 << 5);                                       //original:0                1bit
    p_adts_header[3] |= (0 << 4);                                       //home:0                    1bit
    p_adts_header[3] |= (0 << 3);                                       //copyright id bit:0        1bit
    p_adts_header[3] |= (0 << 2);                                       //copyright id start:0      1bit
    p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);                      //frame length:value   高2bits

    p_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);                 //frame length:value    中间8bits
    p_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);                    //frame length:value    低3bits
    p_adts_header[5] |= 0x1f;                                           //buffer fullness:0x7ff 高5bits
    p_adts_header[6] = 0xfc;                                            //buffer fullness:0x7ff 低6bits

    return 0;
}

void save_packet_to_file(const AVPacket* pkt, FILE* file) {
    fwrite(pkt->data, 1, pkt->size, file);
}

int test_deMuxer() {

    const char* input_filename = "../test_video/d2.mp4";
    const char* video_output_filename = "../test_video/output_video.h264"; // 或者其他格式,取决于视频编码
    const char* audio_output_filename = "../test_video/output_audio.aac";  // 或者其他格式,取决于音频编码

    AVFormatContext* fmt_ctx = nullptr;
    if (avformat_open_input(&fmt_ctx, input_filename, nullptr, nullptr) != 0) {
        std::cerr << "Could not open input file." << std::endl;
        return -1;
    }

    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
        std::cerr << "Could not find stream information." << std::endl;
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    AVCodecParameters* video_codecpar = nullptr;
    AVCodecParameters* audio_codecpar = nullptr;
    int video_stream_index = -1;
    int audio_stream_index = -1;

    // 查找视频流和音频流
    for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
        AVCodecParameters* codecpar = fmt_ctx->streams[i]->codecpar;
        AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);
        if (codec->type == AVMEDIA_TYPE_VIDEO) {
            video_codecpar = codecpar;
            video_stream_index = i;
        }
        else if (codec->type == AVMEDIA_TYPE_AUDIO) {
            audio_codecpar = codecpar;
            audio_stream_index = i;
        }
    }

    // std::cout << "---" << video_stream_index << ", " << audio_stream_index << std::endl;

    if (video_stream_index == -1) {
        std::cerr << "Could not find a video stream." << std::endl;
        avformat_close_input(&fmt_ctx);
        return -1;
    }
    if (audio_stream_index == -1) {
        std::cerr << "Could not find an audio stream." << std::endl;
        // 可以选择继续处理视频流,或者退出程序
        // avformat_close_input(&fmt_ctx);
        // return -1;
    }

    // 打开输出文件
    FILE* video_file, *audio_file;
    errno_t err = fopen_s(&video_file, video_output_filename, "wb");
    if (err != 0) {
        std::cerr << "Could not open video output file." << std::endl;
        avformat_close_input(&fmt_ctx);
        return -1; 
    }

    err = fopen_s(&audio_file, audio_output_filename, "wb");
    if (err != 0 && audio_stream_index != -1) {
        std::cerr << "Could not open audio output file." << std::endl;
        fclose(video_file);
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    const AVBitStreamFilter* bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
    if (!bsfilter)
    {
        std::cerr << "av_bsf_get_by_name." << std::endl;
        fclose(video_file);
        fclose(audio_file);
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    AVBSFContext* bsf_ctx = NULL;
    int ret = av_bsf_alloc(bsfilter, &bsf_ctx);
    if (ret < 0)
    {
        std::cerr << "av_bsf_alloc." << std::endl;
        fclose(video_file);
        fclose(audio_file);
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    ret = avcodec_parameters_copy(bsf_ctx->par_in, fmt_ctx->streams[video_stream_index]->codecpar); //拷贝属性
    if (ret < 0)
    {
        std::cerr << "avcodec_parameters_copy." << std::endl;
        fclose(video_file);
        fclose(audio_file);
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    ret = av_bsf_init(bsf_ctx);
    if (ret < 0)
    {
        std::cerr << "av_bsf_init." << std::endl;
        fclose(video_file);
        fclose(audio_file);
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    AVPacket pkt;
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == video_stream_index) {
            //处理视频
            ret = av_bsf_send_packet(bsf_ctx, &pkt);
            if (ret < 0)
            {
                std::cerr << "av_bsf_send_packet." << std::endl;
                continue;
            }

            ret = av_bsf_receive_packet(bsf_ctx, &pkt);
            if (ret != 0) {
                std::cerr << "av_bsf_receive_packet." << std::endl;
                break;
            }
            save_packet_to_file(&pkt, video_file);
        }
        else if (pkt.stream_index == audio_stream_index) {
            // 注意:对于AAC音频,MP4容器中的原始数据可能不包含ADTS头。
            // 如果需要ADTS头,你需要在保存之前手动添加。
            //处理音频
            uint8_t adts_header_buf[7] = { 0 };
            //添加adts头部信息
            adts_header(adts_header_buf, pkt.size,
                fmt_ctx->streams[audio_stream_index]->codecpar->profile,
                fmt_ctx->streams[audio_stream_index]->codecpar->sample_rate,
                fmt_ctx->streams[audio_stream_index]->codecpar->channels);

            //写adts header
            fwrite(adts_header_buf, 1, 7, audio_file);

            save_packet_to_file(&pkt, audio_file);
        }
        av_packet_unref(&pkt);
    }

    fclose(video_file);
    if (audio_file) {
        fclose(audio_file);
    }
    avformat_close_input(&fmt_ctx);

    return 0;
}

3、DeCoder_H264.cpp


#include "DeCoder.h"

int test_deCoderH264() {
    const char* input_filename = "../test_video/output_video.h264";
    const char* output_yuv = "../test_video/output_video.yuv";

    AVFormatContext* fmt_ctx = nullptr;
    if (avformat_open_input(&fmt_ctx, input_filename, nullptr, nullptr) != 0) {
        std::cerr << "Could not open input file." << std::endl;
        return -1;
    }

    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
        std::cerr << "Could not find stream information." << std::endl;
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    AVCodecParameters* codecpar = nullptr;
    AVCodec* codec = nullptr;
    AVPacket* pkt = av_packet_alloc();
    AVFrame* frameYUV = av_frame_alloc();
    SwsContext* sws_ctx = nullptr;
    int video_stream_index = -1;
    
    for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
        if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            codecpar = fmt_ctx->streams[i]->codecpar;
            // 查找对应解码器
            codec = avcodec_find_decoder(codecpar->codec_id);
            break;
        }
    }
    std::cout << "-------" << fmt_ctx->nb_streams << std::endl;
    if (video_stream_index == -1) {
        std::cerr << "Could not find a video stream." << std::endl;
        av_packet_free(&pkt);
        av_frame_free(&frameYUV);
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    // 创建解码器上下文
    AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
    if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
        std::cerr << "Could not copy codec parameters to context." << std::endl;
        av_packet_free(&pkt);
        av_frame_free(&frameYUV);
        avcodec_free_context(&codec_ctx);
        avformat_close_input(&fmt_ctx);
        return -1;
    }
    std::cout << "-------" << codec_ctx->width << ", " << codec_ctx->height << std::endl;
    // 打开解码器
    if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
        std::cerr << "Could not open codec." << std::endl;
        av_packet_free(&pkt);
        av_frame_free(&frameYUV);
        avcodec_free_context(&codec_ctx);
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    // 32位字节对齐的方式计算缓冲区大小
    int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height, 32);
    uint8_t* buffer = (uint8_t*)av_malloc(num_bytes * sizeof(uint8_t));
    av_image_fill_arrays(frameYUV->data, frameYUV->linesize, buffer, AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height, 1);
    FILE* yuvFile, *yuvFileY;
    errno_t err = fopen_s(&yuvFile, output_yuv, "wb");
    if (err != 0) {
        std::cerr << "Could not open output_filename file." << std::endl;
        av_packet_free(&pkt);
        av_frame_free(&frameYUV);
        avcodec_free_context(&codec_ctx);
        avformat_close_input(&fmt_ctx);
        return -1;
    }
    
    while (av_read_frame(fmt_ctx, pkt) >= 0) {
        if (pkt->stream_index == video_stream_index) {
            if (avcodec_send_packet(codec_ctx, pkt) == 0) {
                while (avcodec_receive_frame(codec_ctx, frameYUV) == 0) {

                    // YUV存入另一个文件
                    fwrite(frameYUV->data[0], 1, codec_ctx->width * codec_ctx->height, yuvFile);
                    fwrite(frameYUV->data[1], 1, codec_ctx->width * codec_ctx->height/4, yuvFile);
                    fwrite(frameYUV->data[2], 1, codec_ctx->width * codec_ctx->height/4, yuvFile);
                }
            }
        }
        av_packet_unref(pkt);
    }
    fclose(yuvFile);
    av_frame_free(&frameYUV);
    avcodec_free_context(&codec_ctx);
    av_packet_free(&pkt);
    avformat_close_input(&fmt_ctx);
    av_free(buffer);

    return 0;
}

4、DeCoder_AAC.cpp

#include "DeCoder.h"

int test_deCoderAac(){
    
    const char* input_file = "../test_video/output_audio.aac";
    const char* output_file = "../test_video/output_audio.pcm";

    // 打开输入文件
    AVFormatContext* fmt_ctx = nullptr;
    if (avformat_open_input(&fmt_ctx, input_file, nullptr, nullptr) < 0) {
        std::cerr << "Could not open input file\n";
        return 1;
    }

    // 查找流信息
    if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
        std::cerr << "Could not find stream information\n";
        return 1;
    }

    // 查找音频流
    int audio_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
    if (audio_stream_index < 0) {
        std::cerr << "Could not find audio stream\n";
        return 1;
    }

    // 获取解码器参数
    AVCodecParameters* codec_params = fmt_ctx->streams[audio_stream_index]->codecpar;

    // 查找解码器
    const AVCodec* codec = avcodec_find_decoder(codec_params->codec_id);
    if (!codec) {
        std::cerr << "Unsupported codec\n";
        return 1;
    }

    // 创建解码器上下文
    AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
    if (avcodec_parameters_to_context(codec_ctx, codec_params) < 0) {
        std::cerr << "Could not initialize codec context\n";
        return 1;
    }

    // 打开解码器
    if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
        std::cerr << "Could not open codec\n";
        return 1;
    }

    // 准备重采样器(AAC解码后通常为FLTP格式,转换为S16格式)
    SwrContext* swr = swr_alloc_set_opts(nullptr,
        AV_CH_LAYOUT_STEREO,      // 输出声道布局
        AV_SAMPLE_FMT_S16,        // 输出格式
        codec_ctx->sample_rate,   // 输出采样率
        codec_ctx->channel_layout ?
        codec_ctx->channel_layout :
        av_get_default_channel_layout(codec_ctx->channels), // 输入声道布局
        codec_ctx->sample_fmt,    // 输入格式
        codec_ctx->sample_rate,   // 输入采样率
        0, nullptr);
    
    // 检查重采样器初始化
    if (!swr || swr_init(swr) < 0) {
        std::cerr << "Failed to initialize resampler\n";
        return 1;
    }

    // 准备数据包和帧
    AVPacket* pkt = av_packet_alloc();
    AVFrame* frame = av_frame_alloc();

    // 打开输出文件
    std::ofstream outfile(output_file, std::ios::binary);
    if (!outfile.is_open()) {
        std::cerr << "Could not open output file\n";
        return 1;
    }

    // 解码循环
    while (av_read_frame(fmt_ctx, pkt) >= 0) {
        if (pkt->stream_index == audio_stream_index) {
            // 发送数据包到解码器
            if (avcodec_send_packet(codec_ctx, pkt) < 0) {
                std::cerr << "Error sending packet\n";
                continue;
            }

            // 接收解码后的帧
            while (avcodec_receive_frame(codec_ctx, frame) >= 0) {
                // 检查帧有效性
                if (frame->nb_samples == 0 || !frame->data) {
                    continue;
                }
                // 分配输出缓冲区
                uint8_t* output_buffer = nullptr;
                int out_linesize;
                int ret = av_samples_alloc(&output_buffer, &out_linesize,
                    2,  // 输出声道数(立体声)
                    frame->nb_samples,
                    AV_SAMPLE_FMT_S16, 0);
                if (ret < 0) {
                    std::cerr << "Failed to allocate samples\n";
                    continue;
                }

                // 重采样
                int sample_count = swr_convert(swr,
                    &output_buffer, frame->nb_samples,
                    (const uint8_t**)frame->data, frame->nb_samples);

                // 写入PCM数据
                if (sample_count > 0) {
                    int data_size = av_samples_get_buffer_size(nullptr, 2,
                        sample_count,
                        AV_SAMPLE_FMT_S16, 1);
                    outfile.write(reinterpret_cast<char*>(output_buffer), data_size);
                }

                av_freep(&output_buffer);
            }
        }
        av_packet_unref(pkt);
    }

    // 清理资源
    av_packet_free(&pkt);
    av_frame_free(&frame);
    swr_free(&swr);
    avcodec_free_context(&codec_ctx);
    avformat_close_input(&fmt_ctx);
    outfile.close();

    std::cout << "Decoding completed successfully\n";
    return 0;
}

5、main.cpp

#include "DeCoder.h"

int main() {
    av_log_set_level(AV_LOG_DEBUG);
	test_deMuxer();
	test_deCoderH264();
    test_deCoderAac();
	return 0;
}

上述代码已验证通过,笔者用的运行环境是VS2019,所用的ffmpeg4.4.5库是自己编译的x64库。项目路径下载地址:https://download.youkuaiyun.com/download/ddazz0621/90519707;运行成功最终生成如下文件:

需要注意:想验证最后生成的pcm播放,调用ffplay执行如下命令:

ffplay -f s16le -ar 8000 -ac 2 output_audio.pcm

一文读懂 Android FFmpeg 视频解码过程与实战分析 动手点关注干货不迷路????概述本文首先以 FFmpeg 视频解码为主题,主要介绍了 FFmpeg 进行解码视频时的主要流程、基本原理;其次,文章还讲述了与 FFmpeg 视频解码有关的简单... 阅读详情

相关推荐

ffmpeg的对象架构简析——解复用器

看这篇文章你需要对ffmpeg已经有一定的使用经验,知道如何read帧,解帧,或者write等。 ffmpeg内部使用跑结构体表函数指针的方式,实现了类似C++的多态性,,我们来简析一下。 【注册表】 我们使用ffmpeg,首先要执行av_register_all,这个玩意儿把全局的解码器、编码器等结构体注册到一些全局的对象表里,以便后面跑表调用。 注册的类型有:解复用器、重复用器、解

a1875566250的专栏 3970

基于NDK、C++、FFmpeg的android视频播放器开发实战

课程包含了对流媒体(拉流)的播放,演示了播放rtmp的香港卫视,支持rtsp摄像头和http网络视频的播放,支持访问本地的视频文件,并精确显示和控制播放进度:1讲解如何编译Android平台的ffmpeg库,使其支持neon技术和硬解码,并测试性能2使用opengles的NDK shader高效播放yuv视频,不耗费cpu性能更优(GPU)3代码支持硬解码(省电不耗cpu)和多线程解码(高性能每秒解码240帧1080p)4支持网络流媒体(rtmp,rtsp,http)可直接拉流播放电视并支持rtsp摄像头访问5课程将设计模式应用到实践 - 观察者,构建者,门面,代理,适配器,单件模式

从零实现简易播放器:4.ffmpeg 解码视频为yuv数据-使用avcodec_send_packet与avcodec_receive_frame

ffmpeg 解码视频为yuv数据 作者:史正 邮箱:shizheng163@126.com 如有错误还请及时指正 如果有错误的描述给您带来不便还请见谅 如需交流请发送邮件,欢迎联系 csdn : https://blog.youkuaiyun.com/shizheng163 github : https://github.com/shizheng163 文章目录ffmpeg 解码视频为yuv数据简...

shizheng163的博客 3341

C++调用ffmpeg sdk开发

一开始我想直接就用输入源的参数,参数太多了懒得一个一个报错了再去改,谁知道错的离谱,代码里面我自己设定了几个参数,可能不太全,但是代码可以运行了,结果也是准确的,还是不错的,毕竟自己也是刚开始学习。首先整体的流程,在网上看到有大佬给出了基于ffmpeg格式转换的流程,如下图,是FLV转到AVI的,我只有几个MP4文件,所以就参考大佬的流程做一个MP4转AVI吧。...本来想通过实现各个格式的相互转换来熟悉ffmpeg的,但是发现内容有点多,就只实现了mp4转成avi格式。总体来说流程还不是太难。

XiaoWuiiii的博客 4902

FFmpeg深入分析之零-基础

FFmpeg是相当强大的多媒体编解码框架,在深入分析其源代码之前必须要有基本的多媒体基础知识,否则其源代码会非常晦涩难懂。本文将从介绍一些基本的多媒体只是,主要是为研读ffmpeg源代码做准备,比如一些编解码部分,只有真正了解了多媒体处理的基本流程,研读ffmpeg源代码才能事半功倍。 下面分析一下多媒体中最基本最核心的视频解码过程,平常我们从网上下载一部电影或者一首歌曲,那么相应的多

三哥的技术专栏 2315

C/C++音视频高级开发 FFmpeg编程入门

一、播放器框架 常用音视频术语 容器/文件(Conainer/File):即特定格式的多媒体文件,比如mp4、flv、mkv等。 媒体流(Stream):表示时间轴上的一段连续数据,如一段声音数据、一段视频数据或一段字幕数据,可以是压缩的,也可以是非压缩的,压缩的数据需要关联特定的编解码器(有些码流音频他是纯PCM)。 数据帧/数据包(Frame/Packet):通常,一个媒体流是由大量的数据帧组成的,对于压缩数据,帧对应着编解码器的最小处理单元,分属于不同媒体流的数据帧交错存储于容器之中。

yinshipin007的博客 3940

解复用FLV文件(基于FFMPEG解析FLV(h264+aac))

技术在于交流、沟通,转载请注明出处并保持作品的完整性。 原文: https://blog.youkuaiyun.com/hiwubihe/article/details/82346759 [本系列相关文章] H264和音频流打包成PS流 (MPEG2-PS) PS流解复用成H264和音频流(ES提取) H264和音频流打包成TS流 (MPEG2-TS) TS流解复用成H264和音频流(ES提取)...

音视频技术之路QQ_1695710968 6714

Qt/C++音视频开发:使用FFmpeg内核进行硬解码

然后,打开输入文件,检索流信息,并查找视频流索引。总结来说,使用FFmpeg库进行音视频硬解码是一种强大的工具,可以在Qt/C++环境下实现高效的音视频处理。通过上述示例代码,你可以开始在你的项目中使用FFmpeg进行音视频硬解码,并根据需要进行自定义的处理和扩展。在实际应用中,还需根据需求进行相应的处理,比如音频解码、音频输出、错误处理等。在音视频开发中,使用FFmpeg内核进行硬解码是一种常见的技术手段。本文将介绍如何在Qt/C++环境下使用FFmpeg库进行音视频硬解码,并提供相应的源代码示例。

CodeJolt的博客 470

ffmpeg解复用编解码 常用API大全给出详细中文解释

ffmpeg常见api 打上详细中文注释

qq_16401691的博客 2257

使用 FFmpeg 处理视频:简介、常用命令及在 C++ 中调用 FFmpeg

FFmpeg 是一个开源的跨平台音视频处理工具,它提供了丰富的功能和命令行工具,可以用于处理、转换和流处理各种音视频格式。本文将介绍 FFmpeg 的基本概念、常用命令及如何在 C++ 中调用 FFmpeg 处理视频。FFmpeg 是一个集成了音视频编解码库、格式转换库等多种库的跨平台开源项目。它提供了命令行工具和库文件,可以在不同的操作系统上进行音视频的采集、编码、解码、转码、流处理等操作。本文介绍了 FFmpeg 的基本概念、常用命令及如何在 C++ 中调用 FFmpeg 处理视频。

MusicScore的博客 1697

以FLV解复用为例详解开源库FFmpeg中解复用器的源码逻辑及处理流程

本文以FLV音视频解复用为例,详细讲解开源库FFmpeg中解复用器的源码逻辑及处理流程。

dvlinker的技术专栏 1万+

FFmpeg 4.3 H265 十八,ffmpeg解复用

1.封装就相当于将 h264 和aac 包裹在一起。既能播放声音,也能播放视频2.在封装的时候没指定编码格式,帧率,时长,等参数;特别是视频,可以将视频帧索引存储,方便视频进度跳转。

hunandede的博客 635

【FFmpeg 系列】 音视频解复用与复用实战

FFmpeg 实战解复用与复用

世界那么大,我想去看看~【随心更新,看世界去了😄】 710

FFmpeg的解复用器

看这篇文章你需要对ffmpeg已经有一定的使用经验,知道如何read帧,解帧,或者write等。 ffmpeg内部使用跑结构体表函数指针的方式,实现了类似C++的多态性,,我们来简析一下。 【注册表】 我们使用ffmpeg,首先要执行av_register_all,这个玩意儿把全局的解码器、编码器等结构体注册到一些全局的对象表里,以便后面跑表调用。 注册的类型有:解复用器、重复用器、解

RunningZyx的博客 1624

FFmpeg解复用器如何从封装格式中解析出不同的音视频数据

本文讲述FFmpeg解复用器如何从封装格式中解析出不同的音视频数据。

dvlinker的技术专栏 547

FFmpeg音频解码实战教程

FFmpeg是一个非常强大的多媒体处理框架,支持几乎所有格式的视频和音频的录制、转换、流处理。它是由一系列命令行工具和一个库组成的,该库能够解码、编码、复用、解复用、流处理、过滤和播放几乎所有已知的视频和音频格式。在程序执行完毕后,我们应当确保所有资源被正确释放,避免内存泄漏或其他潜在的问题。FFmpeg库的资源清理涉及到关闭解码器和释放解码上下文。随着项目接近尾声,我们来回顾一下完成的成果,以及存在的不足之处,并对未来的工作进行展望。

weixin_42515392的博客 1137

如何设置解复用器参数

解复用器 (demuxer)的参数 分为 通用部分 跟 私有部分。通用部分是指所有文件格式都有的属性,例如 formatprobesize 是 MP4 跟 FLV都有的属性。而 export_all 是只有 MP4 自己才有的属性。

u012117034的博客 3914

labview的TDMS文件读写

本文先介绍TDMS概念和文件结构,然后介绍VI如何使用,最后分析一个labview的自带范例

观则明的博客 1万+
上一篇: C++操作符重载案例
下一篇: Ubuntu22.04搭建基于GPU的Yolov8环境
码农诗人
博客等级 码龄11年 987粉丝 84原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值