ffmpeg - Muxing with libav -
i have program supposed demux input mpeg-ts, transcode mpeg2 h264 , mux audio alongside transcoded video. when open resulting muxed file vlc neither audio nor video. here relevant code.
my main worker loop follows:
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 avformat_write_header(output_context, null); //do not start doing until 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 memory barrier required here don't race //on above variables //fill buffer 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 have full frame per packet? write_video_frame(output_context, video_stream, ctx, &mux_state); //write full video frame //encoded_video_queue being filled previous command } av_write_trailer(output_context); //free resources avcodec_close(video_stream->codec); avcodec_close(audio_stream->codec); /* free streams. */ (int = 0; < 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 output file. */ avio_close(output_context->pb); } /* free stream */ av_free(output_context); free(mux_state.pps); free(mux_state.sps); }
the code initialising libav output context this:
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 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; (int = 0; < 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 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) { /* care 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 crash on .mkvs attachments: */ av_dict_copy(&output_stream->metadata, input_stream->metadata, 0); /* reset codec tag not cause problems output format */ output_stream->codec->codec_tag = 0; audio_copied = 1; } } (int = 0; < 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 output context\n"); exit(1); } } return oc; }
finally code writing audio:
static void write_audio_frame(avformatcontext *oc, avstream *st, struct transcoder_ctx_t *ctx) { avpacket pkt = {0}; // data , size must 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 compressed frame 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); }
a resulting mpeg4 file can obtained here: http://87.120.131.41/dl/mpeg4.h264
i have ommited write_video_frame code since lot more complicated , might making wrong there i'm doing timebase conversation etc. audio i'm doing 1:1 copy. each packet_t packet contains data av_read_frame input mpegts container. in worst case i'd expect audio working , not video. cannot either of work. seems documentation rather vague on making things - i've tried both libav , ffmpeg irc channels no avail. information regarding how can debug issue appreciated.
when different containers yield different results in libav timebase issue. containers have time_base like, , accept custom values... sometimes.
you must rescale time base before putting in container. tinkering mux state struct isn't want , think did there doesn't think. try printing out of timebases find out are.
each frame must recalculate pts @ least. if before call encode encoder produce proper dts. same audio, set dts av_no_pts , can away setting audio pts well. rescale use av_rescale(...) functions.
be careful assuming have mpeg-2 data in mpeg-ts container, not true.
Comments
Post a Comment