Mainly the next few functions
First is the basic definition of the main function
VideoState *is; is = av_mallocz(sizeof(VideoState)); if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } is->pictq_mutex = SDL_CreateMutex(); is->pictq_cond = SDL_CreateCond(); //set timer //Set callback timer rendering! Render every 40ms Here's the rendering schedule_refresh(is, 40);
Then start the unwrapping thread
is->parse_tid = SDL_CreateThread(decode_thread, "decode_thread", is);
Open Unpacking decode_thread()
Get file information if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL)!=0) Getting Stream index for(i=0; i<pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index=i; } if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && audio_index < 0) { audio_index=i; } } if(audio_index >= 0) { //Initialize Various stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } SDL Initialization win = SDL_CreateWindow("Media Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, is->video_ctx->width, is->video_ctx->height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); renderer = SDL_CreateRenderer(win, -1, 0); pixformat = SDL_PIXELFORMAT_IYUV; texture = SDL_CreateTexture(renderer, pixformat, SDL_TEXTUREACCESS_STREAMING, is->video_ctx >width, is->video_ctx->height); // Cyclic Unpacking for(;;) { if(is->quit) { SDL_CondSignal(is->videoq.cond); SDL_CondSignal(is->audioq.cond); break; } // seek stuff goes here if(is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_VIDEOQ_SIZE) { SDL_Delay(10); continue; } if(av_read_frame(is->pFormatCtx, packet) < 0) { if(is->pFormatCtx->pb->error == 0) { SDL_Delay(100); /* no error; wait for user input */ continue; } else { break; } } // Is this a packet from the video stream? if(packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); //fprintf(stderr, "put video queue, size :%d\n", is->videoq.nb_packets); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); //fprintf(stderr, "put audio queue, size :%d\n", is->audioq.nb_packets); } else { av_free_packet(packet); } } // Determine what stream queues the demultiplexed pkt if(packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); //fprintf(stderr, "put video queue, size :%d\n", is->videoq.nb_packets); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); //fprintf(stderr, "put audio queue, size :%d\n", is->audioq.nb_packets); } else { av_free_packet(packet); } }
Initialization and decoding-related function stream_component_open(is, video_index);
Initializing parameters and creating video decoding threads
General Initialization int64_t in_channel_layout, out_channel_layout; AVFormatContext *pFormatCtx = is->pFormatCtx; AVCodecContext *codecCtx = NULL; AVCodec *codec = NULL; SDL_AudioSpec wanted_spec, spec; Initialize decoder based on stream information codec = avcodec_find_decoder(pFormatCtx->streams[stream_index]->codec->codec_id); codecCtx = avcodec_alloc_context3(codec); Determine flow type, flow type, operation case AVMEDIA_TYPE_AUDIO: case AVMEDIA_TYPE_VIDEO:
case AVMEDIA_TYPE_AUDIO:
Various Initializations
//First pass in the audio parameter to ensure that the device can turn on 2 sets the callback function decode the callback function audio_callback and callback parameters if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) { // Set audio settings from codec info wanted_spec.freq = codecCtx->sample_rate; wanted_spec.format = AUDIO_S16SYS; wanted_spec.channels = 2; wanted_spec.silence = 0; wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; wanted_spec.callback = audio_callback; wanted_spec.userdata = is; if(SDL_OpenAudio(&wanted_spec, &spec) < 0) { fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); return -1; } }; Initialization audiostream Related parameters is->audioStream = stream_index; is->audio_st = pFormatCtx->streams[stream_index]; is->audio_ctx = codecCtx; is->audio_buf_size = 0; is->audio_buf_index = 0; open up pktk space memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); //Initialize Queue packet_queue_init(&is->audioq); //Turn on playing audio SDL_PauseAudio(0); //Out Audio Param Set Resampling Related Parameters to Initialize Resampling uint64_t out_channel_layout=AV_CH_LAYOUT_STEREO; //AAC:1024 MP3:1152 int out_nb_samples= is->audio_ctx->frame_size; //AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; int out_sample_rate=is->audio_ctx->sample_rate; int out_channels=av_get_channel_layout_nb_channels(out_channel_layout); //Out Buffer Size /* int out_buffer_size=av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, AV_SAMPLE_FMT_S16, 1); */ //uint8_t *out_buffer=(uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE*2); int64_t in_channel_layout=av_get_default_channel_layout(is->audio_ctx->channels); struct SwrContext *audio_convert_ctx = NULL; audio_convert_ctx = swr_alloc(); if(!audio_convert_ctx){ printf("Failed to swr_alloc\n"); return -1; } swr_alloc_set_opts(audio_convert_ctx, out_channel_layout, AV_SAMPLE_FMT_S16, out_sample_rate, in_channel_layout, is->audio_ctx->sample_fmt, is->audio_ctx->sample_rate, 0, NULL); swr_init(audio_convert_ctx); is->audio_swr_ctx = audio_convert_ctx;
case AVMEDIA_TYPE_VIDEO
The focus here is on the initialized video decoding thread
is->videoStream = stream_index; is->video_st = pFormatCtx->streams[stream_index]; is->video_ctx = codecCtx; //Initialize Queue packet_queue_init(&is->videoq); is->video_tid = SDL_CreateThread(video_thread, "video_thread", is); is->sws_ctx = sws_getContext(is->video_ctx->width, is->video_ctx->height, is->video_ctx->pix_fmt, is->video_ctx->width, is->video_ctx->height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
Video decoding thread video_thread
Is to loop pkt out of the queue and decode it to frame and place it in the decoded video queue
nt video_thread(void *arg) { VideoState *is = (VideoState *)arg; AVPacket pkt1, *packet = &pkt1; int frameFinished; AVFrame *pFrame; pFrame = av_frame_alloc(); for(;;) { if(packet_queue_get(&is->videoq, packet, 1) < 0) { // means we quit getting packets break; } // Decode video frame avcodec_decode_video2(is->video_ctx, pFrame, &frameFinished, packet); // Did we get a video frame? if(frameFinished) { if(queue_picture(is, pFrame) < 0) { break; } } av_free_packet(packet); } av_frame_free(&pFrame); return 0; }
Audio decoding void audio_in main thread Callback (void *userdata, Uint8 *stream, int len)
First get parameter 1 from the parameter we defined passed in. Buffer 3 buffer size for global context 2 sound card
First judge audio_ If buf has any value in it then go to the queue to get pkt decoding
Then calculate that if the buf length and the buffer length are smaller, all inputs will be larger than the input buffer size only
Then redefine buf based on the amount of incoming data
void audio_callback(void *userdata, Uint8 *stream, int len) { VideoState *is = (VideoState *)userdata; int len1, audio_size; SDL_memset(stream, 0, len); while(len > 0) { if(is->audio_buf_index >= is->audio_buf_size) { /* We have already sent all our data; get more */ audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf)); if(audio_size < 0) { /* If error, output silence */ is->audio_buf_size = 1024*2*2; memset(is->audio_buf, 0, is->audio_buf_size); } else { is->audio_buf_size = audio_size; } is->audio_buf_index = 0; } len1 = is->audio_buf_size - is->audio_buf_index; fprintf(stderr, "stream addr:%p, audio_buf_index:%d, audio_buf_size:%d, len1:%d, len:%d\n", stream, is->audio_buf_index, is->audio_buf_size, len1, len); if(len1 > len) len1 = len; //memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1); //fwrite(is->audio_buf, 1, len1, audiofd1); //fflush(audiofd1); SDL_MixAudio(stream,(uint8_t *)is->audio_buf + is->audio_buf_index, len1, SDL_MIX_MAXVOLUME); len -= len1; stream += len1; is->audio_buf_index += len1; } }
Audio decoding int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size)
Return value is decoded data
Parameter 1 is the global context
Parameter 2 is the buf to fill in the frame
bufsize of parameter 3
Loop decoding
First determine if there is a pkt in the queue that gets decoded every day, then call the previously defined resampling format to resample it, write it to the buffer, and then redefine buf size and buf
After video decoding
Manual callback defines how many seconds to call back a function schedule_refresh()
A callback function sdl_ Refresh_ Timer_ SDL_where cb() sends an event main function Event Receives Events
SDL_ Evet calls video_refresh_timer();
video_refresh_timer(); Is the logic of true video rendering
Inside it, check to see if there is data after the decoded queue, no data for a millisecond, and then again until there is data
With data that sets a schedule_ Refresh (40ms) call again after 40ms and so on
Then refresh the SDL display
nt audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size) { int len1, data_size = 0; AVPacket *pkt = &is->audio_pkt; for(;;) { while(is->audio_pkt_size > 0) { int got_frame = 0; len1 = avcodec_decode_audio4(is->audio_ctx, &is->audio_frame, &got_frame, pkt); if(len1 < 0) { /* if error, skip frame */ fprintf(stderr, "Failed to decode audio ......\n"); is->audio_pkt_size = 0; break; } data_size = 0; if(got_frame) { /* fprintf(stderr, "=====>auido: channels:%d, nb_samples:%d, sample_fmt:%d\n", is->audio_ctx->channels, is->audio_frame.nb_samples, is->audio_ctx->sample_fmt); */ /* data_size = av_samples_get_buffer_size(NULL, is->audio_ctx->channels, is->audio_frame.nb_samples, is->audio_ctx->sample_fmt, 1); */ data_size = 2 * is->audio_frame.nb_samples * 2; assert(data_size <= buf_size); //memcpy(audio_buf, is->audio_frame.data[0], data_size); swr_convert(is->audio_swr_ctx, &audio_buf, MAX_AUDIO_FRAME_SIZE*3/2, (const uint8_t **)is->audio_frame.data, is->audio_frame.nb_samples); fwrite(audio_buf, 1, data_size, audiofd); fflush(audiofd); } is->audio_pkt_data += len1; is->audio_pkt_size -= len1; if(data_size <= 0) { /* No data yet, get more frames */ continue; } /* We have data, return it and come back for more later */ return data_size; } if(pkt->data) av_free_packet(pkt); if(is->quit) { fprintf(stderr, "will quit program......\n"); return -1; } /* next packet */ if(packet_queue_get(&is->audioq, pkt, 1) < 0) { return -1; } is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; } }