gpt4 book ai didi

ffmpeg - 使用 ffmpeg muxer 到 MPEG2TS ,音频流无法在 vlc 播放器中播放

转载 作者:行者123 更新时间:2023-12-04 22:44:41 25 4
gpt4 key购买 nike

我使用 libavformat 将 h264 流和 aac 流封装成可播放的 mp4 文件。但是,封装成ts文件后,在Win10播放器中可以正常工作,但在vlc播放器中没有音频。封装时,打印音频流,但使用 fprobe 时,以 channel=0 打印音频流。这可能是什么原因?
而且h264源文件没有pts。所以我自己计算。
ffprobe print
ffmpeg print
这是我的代码。

#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>


static void log_packet(const AVFormatContext* fmt_ctx, const AVPacket* pkt, const char* tag)
{
AVRational* time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
printf("%s num=%d den=%d\n", tag, time_base->num, time_base->den);
printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
tag,
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
pkt->stream_index);
}

int main()
{
const char* in_filename_v = "test.h264";
const char* in_filename_a = "aoutput.aac";
const char* out_filename = "lol.ts";


//Video Input AVFormatContext
AVFormatContext* ifmt_ctx_v = NULL;
int ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0);
if (ret < 0)
{
fprintf(stderr, "Could not open input_v %s", in_filename_v);
return -1;
}

//Find Video Stream Info
ret = avformat_find_stream_info(ifmt_ctx_v, 0);
if (ret < 0)
{
fprintf(stderr, "Could not find input_v stream info");
return -1;
}

//Audio Input AVFormatContext
AVFormatContext* ifmt_ctx_a = NULL;
ret = avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0);
if (ret < 0)
{
fprintf(stderr, "Could not open input_a %s", in_filename_a);
return -1;
}

//Find Audio Stream Info
ret = avformat_find_stream_info(ifmt_ctx_a, 0);
if (ret < 0)
{
fprintf(stderr, "Could not find input_a stream info");
return -1;
}


printf("===========Input Information==========\n");
av_dump_format(ifmt_ctx_v, 0, in_filename_v, 0);
av_dump_format(ifmt_ctx_a, 0, in_filename_a, 0);
printf("======================================\n");


//Output AVFormatContext
AVFormatContext* ofmt_ctx = NULL;
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx)
{
fprintf(stderr, "cannot alloc OutputFromat context!");
ret = AVERROR_UNKNOWN;
return -1;
}
AVOutputFormat* ofmt = ofmt_ctx->oformat;

//Alloc AVSTREAM
int istream_index_v = 0, istream_index_a = 0, ostream_index_v = 0, ostream_index_a = 0;
for (int i = 0; i < ifmt_ctx_v->nb_streams; i++)
{
AVStream* outstream;
AVStream* in_stream = ifmt_ctx_v->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
continue;

outstream = avformat_new_stream(ofmt_ctx, NULL);
if (!outstream)
{
fprintf(stderr, "Failed allocating output stream\n");
return -1;
}

ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
if (ret < 0)
{
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
outstream->codecpar->codec_tag = 0;
// Remeber video stream id
istream_index_v = i;
ostream_index_v = 0;
break;
}

for (int i = 0; i < ifmt_ctx_a->nb_streams; i++)
{
AVStream* outstream;
AVStream* in_stream = ifmt_ctx_a->streams[i];
AVCodecParameters* in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
continue;

outstream = avformat_new_stream(ofmt_ctx, NULL);
if (!outstream)
{
fprintf(stderr, "Failed allocating output stream\n");
return -1;
}

ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
if (ret < 0)
{
fprintf(stderr, "Failed to copy codec parameters\n");
return -1;
}
outstream->codecpar->codec_tag = 0;
// Remeber audio stream id
istream_index_a = i;
ostream_index_a = 1;
break;
}

printf("===========Output Information==========\n");
av_dump_format(ofmt_ctx, 0, out_filename, 1);
printf("======================================\n");

if (!(ofmt->flags & AVFMT_NOFILE))
{
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0)
{
fprintf(stderr, "Could not open output file '%s'", out_filename);
return -1;
}
}

//Write file header
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
return -1;
}

//read and write packet
AVPacket* pkt = av_packet_alloc();
if (!pkt)
{
fprintf(stderr, "Could not allocate AVPacket\n");
return -1;
}
while (1)
{
AVStream* in_stream, * outstream;
ret = av_read_frame(ifmt_ctx_v, pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx_v->streams[pkt->stream_index];
if (pkt->stream_index != istream_index_v)
{
av_packet_unref(pkt);
continue;
}


pkt->stream_index = ostream_index_v;
outstream = ofmt_ctx->streams[pkt->stream_index];
// in log info
log_packet(ifmt_ctx_v, pkt, "in");

if (pkt->pts == AV_NOPTS_VALUE)
{
AVRational time_base1 = in_stream->time_base;
//
int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
static int frame_index = 0;
pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
pkt->dts = pkt->pts;
pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
frame_index++;
}


// duration between two frames(us)
av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
pkt->pos = -1;
// out log info
log_packet(ofmt_ctx, pkt, "out");

ret = av_interleaved_write_frame(ofmt_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error muxing packet\n");
break;
}
}

while (1)
{
AVStream* in_stream, * outstream;
ret = av_read_frame(ifmt_ctx_a, pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx_a->streams[pkt->stream_index];
if (pkt->stream_index != istream_index_a)
{
av_packet_unref(pkt);
continue;
}

if (pkt->pts == AV_NOPTS_VALUE)
{
AVRational time_base1 = in_stream->time_base;
// duration between two frames(us)
int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
static int frame_index = 0;
pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
pkt->dts = pkt->pts;
pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
frame_index++;
}

// in log info
log_packet(ifmt_ctx_a, pkt, "in");

pkt->stream_index = ostream_index_a;
outstream = ofmt_ctx->streams[pkt->stream_index];


//change timestamp
av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
pkt->pos = -1;
// out log info
log_packet(ofmt_ctx, pkt, "out");

ret = av_interleaved_write_frame(ofmt_ctx, pkt);
if (ret < 0)
{
fprintf(stderr, "Error muxing packet\n");
break;
}
}

//write file trailer
av_write_trailer(ofmt_ctx);


printf("===========Output Information==========\n");
av_dump_format(ofmt_ctx, 0, out_filename, 1);
printf("======================================\n");

}
DVB Insepctor video
DVB Insepctor audio

最佳答案

感谢@aergistal。

  • 原因是 av_interleaved_write_frame有缓冲限制。我
    之前没有想过这个所以我写了所有的视频包
    先写所有的音频包。在ts文件中,前面是
    很多视频包,其次是很多音频包,以及
    最后两个包交错。
  • 由于MPEG-TS是由包组成的流,所以播放器长时间找不到音频包导致没有声音。

  • 这是我可以工作的新代码。
    #include <libavutil/timestamp.h>
    #include <libavformat/avformat.h>
    #define EXTRAL 1

    static void log_packet(const AVFormatContext* fmt_ctx, const AVPacket* pkt, const char* tag)
    {
    AVRational* time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;

    FILE* fp = fopen("fflog.log", "a+");
    char buf[200];
    sprintf(buf, "%s num=%d den=%d\n", tag, time_base->num, time_base->den);
    for (int i = 0; *(buf + i) != '\0'; i++)
    {
    fwrite(buf + i, 1, 1, fp);
    }
    sprintf(buf, "%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
    tag,
    av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
    av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
    av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
    pkt->stream_index);
    for (int i = 0; *(buf + i) != '\0'; i++)
    {
    fwrite(buf + i, 1, 1, fp);
    }
    fclose(fp);
    }

    int main()
    {
    const char* in_filename_v = "test.h264";
    const char* in_filename_a = "aoutput.aac";
    const char* out_filename = "lol.ts";


    AVFormatContext* ifmt_ctx_v = NULL;
    int ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0);
    if (ret < 0)
    {
    fprintf(stderr, "Could not open input_v %s", in_filename_v);
    return -1;
    }

    ret = avformat_find_stream_info(ifmt_ctx_v, 0);
    if (ret < 0)
    {
    fprintf(stderr, "Could not find input_v stream info");
    return -1;
    }

    AVFormatContext* ifmt_ctx_a = NULL;
    ret = avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0);
    if (ret < 0)
    {
    fprintf(stderr, "Could not open input_a %s", in_filename_a);
    return -1;
    }

    ret = avformat_find_stream_info(ifmt_ctx_a, 0);
    if (ret < 0)
    {
    fprintf(stderr, "Could not find input_a stream info");
    return -1;
    }

    #if EXTRAL
    printf("===========Input Information==========\n");
    av_dump_format(ifmt_ctx_v, 0, in_filename_v, 0);
    av_dump_format(ifmt_ctx_a, 0, in_filename_a, 0);
    printf("======================================\n");
    #endif

    AVFormatContext* ofmt_ctx = NULL;
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
    if (!ofmt_ctx)
    {
    fprintf(stderr, "cannot alloc OutputFromat context!");
    ret = AVERROR_UNKNOWN;
    return -1;
    }
    AVOutputFormat* ofmt = ofmt_ctx->oformat;

    int istream_index_v = 0, istream_index_a = 0, ostream_index_v = 0, ostream_index_a = 0;
    for (int i = 0; i < ifmt_ctx_v->nb_streams; i++)
    {
    AVStream* outstream;
    AVStream* in_stream = ifmt_ctx_v->streams[i];
    AVCodecParameters* in_codecpar = in_stream->codecpar;
    if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
    continue;

    outstream = avformat_new_stream(ofmt_ctx, NULL);
    if (!outstream)
    {
    fprintf(stderr, "Failed allocating output stream\n");
    return -1;
    }

    ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
    if (ret < 0)
    {
    fprintf(stderr, "Failed to copy codec parameters\n");
    return -1;
    }
    outstream->codecpar->codec_tag = 0;
    istream_index_v = i;
    ostream_index_v = 0;
    break;
    }

    for (int i = 0; i < ifmt_ctx_a->nb_streams; i++)
    {
    AVStream* outstream;
    AVStream* in_stream = ifmt_ctx_a->streams[i];
    AVCodecParameters* in_codecpar = in_stream->codecpar;
    if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
    continue;
    outstream = avformat_new_stream(ofmt_ctx, NULL);
    if (!outstream)
    {
    fprintf(stderr, "Failed allocating output stream\n");
    return -1;
    }

    ret = avcodec_parameters_copy(outstream->codecpar, in_codecpar);
    if (ret < 0)
    {
    fprintf(stderr, "Failed to copy codec parameters\n");
    return -1;
    }
    outstream->codecpar->codec_tag = 0;
    istream_index_a = i;
    ostream_index_a = 1;
    break;
    }

    #if EXTRAL
    printf("===========Output Information==========\n");
    av_dump_format(ofmt_ctx, 0, out_filename, 1);
    printf("======================================\n");
    #endif
    if (!(ofmt->flags & AVFMT_NOFILE))
    {
    ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
    if (ret < 0)
    {
    fprintf(stderr, "Could not open output file '%s'", out_filename);
    return -1;
    }
    }

    ret = avformat_write_header(ofmt_ctx, NULL);
    if (ret < 0) {
    fprintf(stderr, "Error occurred when opening output file\n");
    return -1;
    }

    AVPacket* pkt = av_packet_alloc();
    if (!pkt)
    {
    fprintf(stderr, "Could not allocate AVPacket\n");
    return -1;
    }
    int64_t pts_v = 0, pts_a = 0;
    while (1)
    {
    if (av_compare_ts(pts_a, ifmt_ctx_a->streams[istream_index_a]->time_base, pts_v, ifmt_ctx_v->streams[istream_index_v]->time_base) <= 0)
    {

    AVStream* in_stream, * outstream;
    ret = av_read_frame(ifmt_ctx_a, pkt);
    if (ret < 0)
    break;
    in_stream = ifmt_ctx_a->streams[pkt->stream_index];
    if (pkt->stream_index != istream_index_a)
    {
    av_packet_unref(pkt);
    continue;
    }

    if (pkt->pts == AV_NOPTS_VALUE)
    {
    AVRational time_base1 = in_stream->time_base;
    int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
    static int frame_index = 0;
    pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
    pkt->dts = pkt->pts;
    pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
    frame_index++;
    }
    pts_a = pkt->pts;
    // in log info
    log_packet(ifmt_ctx_a, pkt, "in audio");

    pkt->stream_index = ostream_index_a;
    outstream = ofmt_ctx->streams[pkt->stream_index];


    av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
    pkt->pos = -1;
    // out log info
    log_packet(ofmt_ctx, pkt, "out audio");

    ret = av_interleaved_write_frame(ofmt_ctx, pkt);
    if (ret < 0)
    {
    fprintf(stderr, "Error muxing packet\n");
    return -1;
    }
    }
    else
    {

    AVStream* in_stream, * outstream;
    ret = av_read_frame(ifmt_ctx_v, pkt);
    if (ret < 0)
    break;
    in_stream = ifmt_ctx_v->streams[pkt->stream_index];
    if (pkt->stream_index != istream_index_v)
    {
    av_packet_unref(pkt);
    continue;
    }


    pkt->stream_index = ostream_index_v;
    outstream = ofmt_ctx->streams[pkt->stream_index];


    if (pkt->pts == AV_NOPTS_VALUE)
    {
    AVRational time_base1 = in_stream->time_base;
    int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
    static int frame_index = 0;
    pkt->pts = (double)(frame_index * calc_duration) / (double)(av_q2d(time_base1) * AV_TIME_BASE);
    pkt->dts = pkt->pts;
    pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1) * AV_TIME_BASE);
    frame_index++;
    }
    pts_v = pkt->pts;

    // in log info
    log_packet(ifmt_ctx_v, pkt, "in video");

    av_packet_rescale_ts(pkt, in_stream->time_base, outstream->time_base);
    pkt->pos = -1;
    // out log info
    log_packet(ofmt_ctx, pkt, "out video");

    ret = av_interleaved_write_frame(ofmt_ctx, pkt);
    if (ret < 0)
    {
    fprintf(stderr, "Error muxing packet\n");
    return -1;
    }
    }
    }


    ret = av_write_trailer(ofmt_ctx);
    if (ret < 0)
    {
    fprintf(stderr, "Error av_write_trailer\n");
    }
    #if EXTRAL
    printf("===========Output Information==========\n");
    av_dump_format(ofmt_ctx, 0, out_filename, 1);
    printf("======================================\n");
    #endif
    av_packet_free(&pkt);
    avformat_close_input(&ifmt_ctx_v);
    avformat_close_input(&ifmt_ctx_a);
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
    avio_closep(&ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
    return 0;
    }

    关于ffmpeg - 使用 ffmpeg muxer 到 MPEG2TS ,音频流无法在 vlc 播放器中播放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70119438/

    25 4 0
    文章推荐: android - 如何在Android上实现实时视频编辑?
    文章推荐: FFmpeg - 非单调递增的 dts 是什么意思?
    文章推荐: html 表单标签换行符
    文章推荐: html - 使用 Bootstrap 在
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com