我有一个程序,它应该demux输入mpeg-ts,将mpeg2转码为h264,然后在转码视频旁边混音。当我用VLC打开结果的混音文件时,我既没有得到音频也没有得到视频。这是相关代码。
我的主要工作循环如下:
void
*writer_thread(void *thread_ctx) {
struct transcoder_ctx_t *ctx = (struct transcoder_ctx_t *) thread_ctx;
AVStream *video_stream = NULL, *audio_stream = NULL;
AVFormatContext *output_context = init_output_context(ctx, &video_stream, &audio_stream);
struct mux_state_t mux_state = {0};
//from omxtx
mux_state.pts_offset = av_rescale_q(ctx->input_context->start_time, AV_TIME_BASE_Q, output_context->streams[ctx->video_stream_index]->time_base);
//write stream header if any
avformat_write_header(output_context, NULL);
//do not start doing anything until we get an encoded packet
pthread_mutex_lock(&ctx->pipeline.video_encode.is_running_mutex);
while (!ctx->pipeline.video_encode.is_running) {
pthread_cond_wait(&ctx->pipeline.video_encode.is_running_cv, &ctx->pipeline.video_encode.is_running_mutex);
}
while (!ctx->pipeline.video_encode.eos || !ctx->processed_audio_queue->queue_finished) {
//FIXME a memory barrier is required here so that we don't race
//on above variables
//fill a buffer with video data
OERR(OMX_FillThisBuffer(ctx->pipeline.video_encode.h, omx_get_next_output_buffer(&ctx->pipeline.video_encode)));
write_audio_frame(output_context, audio_stream, ctx); //write full audio frame
//FIXME no guarantee that we have a full frame per packet?
write_video_frame(output_context, video_stream, ctx, &mux_state); //write full video frame
//encoded_video_queue is being filled by the previous command
}
av_write_trailer(output_context);
//free all the resources
avcodec_close(video_stream->codec);
avcodec_close(audio_stream->codec);
/* Free the streams. */
for (int i = 0; i < output_context->nb_streams; i++) {
av_freep(&output_context->streams[i]->codec);
av_freep(&output_context->streams[i]);
}
if (!(output_context->oformat->flags & AVFMT_NOFILE)) {
/* Close the output file. */
avio_close(output_context->pb);
}
/* free the stream */
av_free(output_context);
free(mux_state.pps);
free(mux_state.sps);
}
初始化libav输出上下文的代码如下:
static
AVFormatContext *
init_output_context(const struct transcoder_ctx_t *ctx, AVStream **video_stream, AVStream **audio_stream) {
AVFormatContext *oc;
AVOutputFormat *fmt;
AVStream *input_stream, *output_stream;
AVCodec *c;
AVCodecContext *cc;
int audio_copied = 0; //copy just 1 stream
fmt = av_guess_format("mpegts", NULL, NULL);
if (!fmt) {
fprintf(stderr, "[DEBUG] Error guessing format, dying\n");
exit(199);
}
oc = avformat_alloc_context();
if (!oc) {
fprintf(stderr, "[DEBUG] Error allocating context, dying\n");
exit(200);
}
oc->oformat = fmt;
snprintf(oc->filename, sizeof(oc->filename), "%s", ctx->output_filename);
oc->debug = 1;
oc->start_time_realtime = ctx->input_context->start_time;
oc->start_time = ctx->input_context->start_time;
oc->duration = 0;
oc->bit_rate = 0;
for (int i = 0; i < ctx->input_context->nb_streams; i++) {
input_stream = ctx->input_context->streams[i];
output_stream = NULL;
if (input_stream->index == ctx->video_stream_index) {
//copy stuff from input video index
c = avcodec_find_encoder(CODEC_ID_H264);
output_stream = avformat_new_stream(oc, c);
*video_stream = output_stream;
cc = output_stream->codec;
cc->width = input_stream->codec->width;
cc->height = input_stream->codec->height;
cc->codec_id = CODEC_ID_H264;
cc->codec_type = AVMEDIA_TYPE_VIDEO;
cc->bit_rate = ENCODED_BITRATE;
cc->time_base = input_stream->codec->time_base;
output_stream->avg_frame_rate = input_stream->avg_frame_rate;
output_stream->r_frame_rate = input_stream->r_frame_rate;
output_stream->start_time = AV_NOPTS_VALUE;
} else if ((input_stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) && !audio_copied) {
/* i care only about audio */
c = avcodec_find_encoder(input_stream->codec->codec_id);
output_stream = avformat_new_stream(oc, c);
*audio_stream = output_stream;
avcodec_copy_context(output_stream->codec, input_stream->codec);
/* Apparently fixes a crash on .mkvs with attachments: */
av_dict_copy(&output_stream->metadata, input_stream->metadata, 0);
/* Reset the codec tag so as not to cause problems with output format */
output_stream->codec->codec_tag = 0;
audio_copied = 1;
}
}
for (int i = 0; i < oc->nb_streams; i++) {
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
oc->streams[i]->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
if (oc->streams[i]->codec->sample_rate == 0)
oc->streams[i]->codec->sample_rate = 48000; /* ish */
}
if (!(fmt->flags & AVFMT_NOFILE)) {
fprintf(stderr, "[DEBUG] AVFMT_NOFILE set, allocating output container\n");
if (avio_open(&oc->pb, ctx->output_filename, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "[DEBUG] error creating the output context\n");
exit(1);
}
}
return oc;
}
最后这是编写音频的代码:
static
void
write_audio_frame(AVFormatContext *oc, AVStream *st, struct transcoder_ctx_t *ctx) {
AVPacket pkt = {0}; // data and size must be 0;
struct packet_t *source_audio;
av_init_packet(&pkt);
if (!(source_audio = packet_queue_get_next_item_asynch(ctx->processed_audio_queue))) {
return;
}
pkt.stream_index = st->index;
pkt.size = source_audio->data_length;
pkt.data = source_audio->data;
pkt.pts = source_audio->PTS;
pkt.dts = source_audio->DTS;
pkt.duration = source_audio->duration;
pkt.destruct = avpacket_destruct;
/* Write the compressed frame to the media file. */
if (av_interleaved_write_frame(oc, &pkt) != 0) {
fprintf(stderr, "[DEBUG] Error while writing audio frame\n");
}
packet_queue_free_packet(source_audio, 0);
}
可以从这里获得生成的mpeg4文件:http://87.120.131.41/dl/mpeg4.h264
我推荐了write_video_frame code,因为它要复杂得多,而且我在做音频的时基对话等时可能会出错,但我做的是1:1拷贝。每个数据包包含来自输入mpegts容器的av读取帧的数据。在最坏的情况下,我希望我的音频工作,而不是我的视频。然而,我无法让这两个都起作用。似乎文档中对制作这样的东西相当模糊——我尝试了libav和ffmpeg-irc频道,但都没有用。任何关于我如何调试该问题的信息都将不胜感激。
当不同的容器在libav中产生不同的结果时,这几乎总是一个时基问题。所有容器都有他们喜欢的time_base,有些会接受自定义值......有时。
在将时基放入容器之前,您必须重新调整时基。通常,修补mux状态结构不是您想做的事情,我认为您在那里所做的并没有按照您的想法进行。尝试打印出所有的时基以找出它们是什么。
每一帧都必须至少重新计算PTS。如果在调用encode之前执行此操作,编码器将生成正确的DTS。对音频也要这样做,但通常会将DTS设置为AV_NO_PTS,有时也可以将音频设置为AV_NO_PTS。要轻松重缩放,请使用av_重缩放(…)功能。
请小心假设您在MPEG-TS容器中有MPEG-2数据,但这并不总是正确的。
双非本科,参加了无数场面试,以下是最近面阿里的总结(来源于网络): 阿里 面经1 简单介绍项目 知道哪些数据结构以及他们的特点 链表增删快,那如何提高其查询效率,有没有什么想法? B+树了解吗?B+树如何范围查询?B+树退化的极端情况是什么? 跳表了解吗? 大顶堆、小顶堆了解吗? 实现长地址请求到服务端,然后服务端重定向短地址给客户端,如何实现长短地址的互相映射? 那我现在有10份数据,有1000
#产品2023笔面经# 去年投简历直接挂 今年投终于收到了笔试 北森题库 40min 10言语理解 10资料分析 10图形推理 51性格测试 形式上和携程、shein的一致,只是性格测评不太一样,求一个面试机会吧
这次是被调岗加面一轮,由于自己的身体状况原因,中间歇了一段时间没有面试,发现距离上次面试已经过去大半个月了。 1.自我介绍 2.介绍一下上段实习主要做什么的,并且进行深挖 3.介绍一下上上段实习是干嘛的,通过什么模型之类的进行工作 4.你觉得你碰到最有挑战的工作是什么 5.为什么投了阿里 6.还投了什么其他公司,并追问为什么没去呢 我:因为没过面试 7.那你觉得面试为什么会没通过 8.读书和工作期
饿了么的数据研发岗位,整体面试体验很好!记录一下我的面(凉)经和反思吧~ 8-9 投递 8-13 行测+性格 8-21 笔试,15选择题,3个编程,我分别是100,90,6 8-25 一面 面试官先自我介绍,然后说大概全程30分钟,然后让我自我介绍。接着问更倾向于做算法还是做开发。有没有大数据,数据开发相关的经验,或者课。 接着问sql常用语句,优化方法。 数据结构相关,排序算法。 手撕代码:两个
双非本科,参加了无数场面试,以下是最近面阿里的总结: 阿里 面经1 简单介绍项目 知道哪些数据结构以及他们的特点 链表增删快,那如何提高其查询效率,有没有什么想法? B+树了解吗?B+树如何范围查询?B+树退化的极端情况是什么? 跳表了解吗? 大顶堆、小顶堆了解吗? 实现长地址请求到服务端,然后服务端重定向短地址给客户端,如何实现长短地址的互相映射? 那我现在有10份数据,有1000个线程来争抢,
然后我尝试这样写音频帧: 问题是我从来不传递这个语句:“if(pkt.stream_index==st->index)”。数据包流索引从来不等于音频流索引。谁能指出我错在哪里? 更新: 顺便说一句,下面的答案没有帮助,因为它假设音频和视频流都来自同一个文件,而在我的情况下,只有音频来自外部源。