int decode_thread(void *arg) { // 上半部分的函数没什么新东西;它的工作就是打开文件和找到视频流和音频流的索引。 // 唯一不同的地方是把格式内容保存到大结构体中。当找到流后,调用另一个将要定义的函数 stream_component_open()。 // 这是一个一般的分离的方法,自从我们设置很多相似的视频和音频解码的代码,我们通过编写这个函数来重用它们。 VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx = NULL; AVPacket pkt1, *packet = &pkt1; // http://www.ffmpeg.org/doxygen/3.1/group__lavu__dict.html#details AVDictionary *io_dict = NULL; // AVDictionary 元数据,Simple key:value store. // http://www.ffmpeg.org/doxygen/3.1/structAVIOInterruptCB.html#details AVIOInterruptCB callback; // Callback for checking whether to abort blocking functions. int video_index = -1; int audio_index = -1; int i; is->videoStream=-1; is->audioStream=-1; global_video_state = is; // will interrupt blocking functions if we quit! callback.callback = decode_interrupt_cb; callback.opaque = is; // http://www.ffmpeg.org/doxygen/3.1/aviobuf_8c.html#ae8589aae955d16ca228b6b9d66ced33d // 使用is->filename的内容初始化is->io_context,用于管理文件的读写 if (avio_open2(&is->io_context, is->filename, 0, &callback, &io_dict)) { fprintf(stderr, "Unable to open I/O for %s\n", is->filename); return -1; } // 从传入的第二个参数获得文件路径,这个函数会读取文件头信息,并把信息保存在 pFormatCtx 结构体当中。 // 这个函数后面两个参数分别是: 指定文件格式、格式化选项,当我们设置为 NULL 或 0 时,libavformat 会自动完成这些工作。 if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL)!=0) return -1; // Couldn't open file is->pFormatCtx = pFormatCtx; // Retrieve stream information // 得到流信息 if(avformat_find_stream_info(pFormatCtx, NULL)<0) return -1; // Couldn't find stream information // Dump information about file onto standard error // 这个函数填充了 pFormatCtx->streams 流信息, 可以通过 dump_format 把信息打印出来: av_dump_format(pFormatCtx, 0, is->filename, 0); // 查找一个音频和视频流 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; } } // stream_component_open()函数的作用是找到解码器,设置音频参数,保存重要信息到大结构体中,然后启动音频和视频线程。 if(audio_index >= 0) { stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } if(is->videoStream < 0 || is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } // main decode loop // 上面都是打开文件和找到视频流和音频流的索引等工作,下面才是主循环 for(;;) { if(is->quit) { 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); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while(!is->quit) { SDL_Delay(100); } fail: { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; }
static int startread(sox_format_t * ft) { priv_t * ffmpeg = (priv_t *)ft->priv; AVFormatParameters params; int ret; int i; ffmpeg->audio_buf_raw = lsx_calloc(1, (size_t)AVCODEC_MAX_AUDIO_FRAME_SIZE + 32); ffmpeg->audio_buf_aligned = ALIGN16(ffmpeg->audio_buf_raw); /* Signal audio stream not found */ ffmpeg->audio_index = -1; /* register all CODECs, demux and protocols */ av_register_all(); /* Open file and get format */ memset(¶ms, 0, sizeof(params)); if ((ret = av_open_input_file(&ffmpeg->ctxt, ft->filename, NULL, 0, ¶ms)) < 0) { lsx_fail("ffmpeg cannot open file for reading: %s (code %d)", ft->filename, ret); return SOX_EOF; } /* Get CODEC parameters */ if ((ret = av_find_stream_info(ffmpeg->ctxt)) < 0) { lsx_fail("ffmpeg could not find CODEC parameters for %s", ft->filename); return SOX_EOF; } /* Now we can begin to play (RTSP stream only) */ av_read_play(ffmpeg->ctxt); /* Find audio stream (FIXME: allow different stream to be selected) */ for (i = 0; (unsigned)i < ffmpeg->ctxt->nb_streams; i++) { AVCodecContext *enc = ffmpeg->ctxt->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_AUDIO && ffmpeg->audio_index < 0) { ffmpeg->audio_index = i; break; } } /* Open the stream */ if (ffmpeg->audio_index < 0 || stream_component_open(ffmpeg, ffmpeg->audio_index) < 0 || ffmpeg->audio_stream < 0) { lsx_fail("ffmpeg could not open CODECs for %s", ft->filename); return SOX_EOF; } /* Copy format info */ ft->signal.rate = ffmpeg->audio_st->codec->sample_rate; ft->encoding.bits_per_sample = 16; ft->encoding.encoding = SOX_ENCODING_SIGN2; ft->signal.channels = ffmpeg->audio_st->codec->channels; ft->signal.length = 0; /* Currently we can't seek; no idea how to get this info from ffmpeg anyway (in time, yes, but not in samples); but ffmpeg *can* seek */ return SOX_SUCCESS; }
int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx = NULL; AVPacket pkt1, *packet = &pkt1; AVDictionary *io_dict = NULL; AVIOInterruptCB callback; int video_index = -1; int audio_index = -1; int i; is->videoStream = -1; is->audioStream = -1; is->audio_need_resample = 0; global_video_state = is; // will interrupt blocking functions if we quit! callback.callback = decode_interrupt_cb; callback.opaque = is; if(avio_open2(&is->io_context, is->filename, 0, &callback, &io_dict)) { fprintf(stderr, "Unable to open I/O for %s\n", is->filename); return -1; } // Open video file if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL) != 0) { return -1; // Couldn't open file } is->pFormatCtx = pFormatCtx; // Retrieve stream information if(avformat_find_stream_info(pFormatCtx, NULL) < 0) { return -1; // Couldn't find stream information } // Dump information about file onto standard error av_dump_format(pFormatCtx, 0, is->filename, 0); // Find the first video stream 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) { stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } if(is->videoStream < 0 && is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } #ifdef __RESAMPLER__ if( audio_index >= 0 && pFormatCtx->streams[audio_index]->codec->sample_fmt != AV_SAMPLE_FMT_S16) { is->audio_need_resample = 1; is->pResampledOut = NULL; is->pSwrCtx = NULL; printf("Configure resampler: "); #ifdef __LIBAVRESAMPLE__ printf("libAvResample\n"); is->pSwrCtx = avresample_alloc_context(); #endif #ifdef __LIBSWRESAMPLE__ printf("libSwResample\n"); is->pSwrCtx = swr_alloc(); #endif // Some MP3/WAV don't tell this so make assumtion that // They are stereo not 5.1 if (pFormatCtx->streams[audio_index]->codec->channel_layout == 0 && pFormatCtx->streams[audio_index]->codec->channels == 2) { pFormatCtx->streams[audio_index]->codec->channel_layout = AV_CH_LAYOUT_STEREO; } else if (pFormatCtx->streams[audio_index]->codec->channel_layout == 0 && pFormatCtx->streams[audio_index]->codec->channels == 1) { pFormatCtx->streams[audio_index]->codec->channel_layout = AV_CH_LAYOUT_MONO; } else if (pFormatCtx->streams[audio_index]->codec->channel_layout == 0 && pFormatCtx->streams[audio_index]->codec->channels == 0) { pFormatCtx->streams[audio_index]->codec->channel_layout = AV_CH_LAYOUT_STEREO; pFormatCtx->streams[audio_index]->codec->channels = 2; } av_opt_set_int(is->pSwrCtx, "in_channel_layout", pFormatCtx->streams[audio_index]->codec->channel_layout, 0); av_opt_set_int(is->pSwrCtx, "in_sample_fmt", pFormatCtx->streams[audio_index]->codec->sample_fmt, 0); av_opt_set_int(is->pSwrCtx, "in_sample_rate", pFormatCtx->streams[audio_index]->codec->sample_rate, 0); av_opt_set_int(is->pSwrCtx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); av_opt_set_int(is->pSwrCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int(is->pSwrCtx, "out_sample_rate", 44100, 0); #ifdef __LIBAVRESAMPLE__ if (avresample_open(is->pSwrCtx) < 0) { #else if (swr_init(is->pSwrCtx) < 0) { #endif fprintf(stderr, " ERROR!! From Samplert: %d Hz Sample format: %s\n", pFormatCtx->streams[audio_index]->codec->sample_rate, av_get_sample_fmt_name(pFormatCtx->streams[audio_index]->codec->sample_fmt)); fprintf(stderr, " To 44100 Sample format: s16\n"); is->audio_need_resample = 0; is->pSwrCtx = NULL;; } } #endif // main decode loop for(;;) { if(is->quit) { break; } // seek stuff goes here if(is->seek_req) { int stream_index = -1; int64_t seek_target = is->seek_pos; if(is->videoStream >= 0) { stream_index = is->videoStream; } else if(is->audioStream >= 0) { stream_index = is->audioStream; } if(stream_index >= 0) { seek_target = av_rescale_q(seek_target, AV_TIME_BASE_Q, pFormatCtx->streams[stream_index]->time_base); } if(av_seek_frame(is->pFormatCtx, stream_index, seek_target, is->seek_flags) < 0) { fprintf(stderr, "%s: error while seeking\n", is->pFormatCtx->filename); } else { if(is->audioStream >= 0) { packet_queue_flush(&is->audioq); packet_queue_put(&is->audioq, &flush_pkt); } if(is->videoStream >= 0) { packet_queue_flush(&is->videoq); packet_queue_put(&is->videoq, &flush_pkt); } } is->seek_req = 0; } 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); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while(!is->quit) { SDL_Delay(100); } fail: { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; } void stream_seek(VideoState *is, int64_t pos, int rel) { if(!is->seek_req) { is->seek_pos = pos; is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0; is->seek_req = 1; } } int main(int argc, char *argv[]) { SDL_Event event; //double pts; VideoState *is; is = av_mallocz(sizeof(VideoState)); if(argc < 2) { fprintf(stderr, "Usage: test <file>\n"); exit(1); } // Register all formats and codecs av_register_all(); if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } // Make a screen to put our video #ifndef __DARWIN__ screen = SDL_SetVideoMode(640, 480, 0, 0); #else screen = SDL_SetVideoMode(640, 480, 24, 0); #endif if(!screen) { fprintf(stderr, "SDL: could not set video mode - exiting\n"); exit(1); } av_strlcpy(is->filename, argv[1], 1024); is->pictq_mutex = SDL_CreateMutex(); is->pictq_cond = SDL_CreateCond(); schedule_refresh(is, 40); is->av_sync_type = DEFAULT_AV_SYNC_TYPE; is->parse_tid = SDL_CreateThread(decode_thread, is); if(!is->parse_tid) { av_free(is); return -1; } av_init_packet(&flush_pkt); flush_pkt.data = (unsigned char *)"FLUSH"; for(;;) { double incr, pos; SDL_WaitEvent(&event); switch(event.type) { case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_LEFT: incr = -10.0; goto do_seek; case SDLK_RIGHT: incr = 10.0; goto do_seek; case SDLK_UP: incr = 60.0; goto do_seek; case SDLK_DOWN: incr = -60.0; goto do_seek; do_seek: if(global_video_state) { pos = get_master_clock(global_video_state); pos += incr; stream_seek(global_video_state, (int64_t)(pos * AV_TIME_BASE), incr); } break; default: break; } break; case FF_QUIT_EVENT: case SDL_QUIT: is->quit = 1; /* * If the video has finished playing, then both the picture and * audio queues are waiting for more data. Make them stop * waiting and terminate normally. */ SDL_CondSignal(is->audioq.cond); SDL_CondSignal(is->videoq.cond); SDL_Quit(); exit(0); break; case FF_ALLOC_EVENT: alloc_picture(event.user.data1); break; case FF_REFRESH_EVENT: video_refresh_timer(event.user.data1); break; default: break; } } return 0; }
int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx = NULL; AVPacket pkt1, *packet = &pkt1; AVDictionary *io_dict = NULL; AVIOInterruptCB callback; int video_index = -1; int audio_index = -1; int i; is->videoStream=-1; is->audioStream=-1; global_video_state = is; // will interrupt blocking functions if we quit! callback.callback = decode_interrupt_cb; callback.opaque = is; if (avio_open2(&is->io_context, is->filename, 0, &callback, &io_dict)) { fprintf(stderr, "Unable to open I/O for %s\n", is->filename); return -1; } // Open video file if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL)!=0) return -1; // Couldn't open file is->pFormatCtx = pFormatCtx; // Retrieve stream information if(avformat_find_stream_info(pFormatCtx, NULL)<0) return -1; // Couldn't find stream information // Dump information about file onto standard error av_dump_format(pFormatCtx, 0, is->filename, 0); // Find the first video stream 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) { stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } if(is->videoStream < 0 || is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } // main decode loop for(;;) { if(is->quit) { 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); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while(!is->quit) { SDL_Delay(100); } fail: { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; }
static void *decode_thread(ALLEGRO_THREAD *t, void *arg) { VideoState *is = (VideoState *) arg; AVFormatContext *format_context = is->format_context; AVPacket pkt1, *packet = &pkt1; is->videoStream = -1; is->audioStream = -1; if (is->audio_index >= 0) { stream_component_open(is, is->audio_index); } if (is->video_index >= 0) { stream_component_open(is, is->video_index); } if (is->videoStream < 0 && is->audioStream < 0) { ALLEGRO_ERROR("%s: could not open codecs\n", is->filename); goto fail; } for (;;) { if (is->quit) { break; } if (is->seek_req) { int stream_index = -1; int64_t seek_target = is->seek_pos; if (is->videoStream >= 0) stream_index = is->videoStream; else if (is->audioStream >= 0) stream_index = is->audioStream; if (stream_index >= 0) { seek_target = av_rescale_q(seek_target, AV_TIME_BASE_Q, format_context->streams[stream_index]->time_base); } if (av_seek_frame(is->format_context, stream_index, seek_target, is->seek_flags) < 0) { ALLEGRO_WARN("%s: error while seeking (%d, %lu)\n", is->format_context->filename, stream_index, seek_target); } else { if (is->audioStream >= 0) { packet_queue_flush(&is->audioq); packet_queue_put(&is->audioq, &flush_pkt); } if (is->videoStream >= 0) { packet_queue_flush(&is->videoq); packet_queue_put(&is->videoq, &flush_pkt); } } is->seek_req = 0; is->after_seek_sync = true; } if (is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_VIDEOQ_SIZE) { al_rest(0.01); continue; } if (av_read_frame(is->format_context, packet) < 0) { #ifdef FFMPEG_0_8 if (!format_context->pb->eof_reached && !format_context->pb->error) { #else if (url_ferror((void *)&format_context->pb) == 0) { #endif al_rest(0.01); continue; } else { break; } } // Is this a packet from the video stream? if (packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); } else if (packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while (!is->quit) { al_rest(0.1); } fail: return t; } /* We want to be able to send an event to the user exactly at the time * a new video frame should be displayed. */ static void *timer_thread(ALLEGRO_THREAD *t, void *arg) { VideoState *is = (VideoState *) arg; double ot = 0, nt = 0; while (!is->quit) { ALLEGRO_EVENT event; double d; /* Wait here until someone signals to us when a new frame was * scheduled at is->show_next. */ al_lock_mutex(is->timer_mutex); al_wait_cond(is->timer_cond, is->timer_mutex); al_unlock_mutex(is->timer_mutex); if (is->quit) break; /* Wait until that time. This wait is why we have our own thread * here so the user doesn't need to do it. */ while (1) { d = is->show_next - get_master_clock(is); if (d <= 0) break; //printf("waiting %4.1f ms\n", d * 1000); al_rest(d); } nt = get_master_clock(is); //printf("event after %4.1f ms\n", (nt - ot) * 1000); ot = nt; /* Now is the time. */ event.type = ALLEGRO_EVENT_VIDEO_FRAME_SHOW; event.user.data1 = (intptr_t)is->video; al_emit_user_event(&is->video->es, &event, NULL); } return t; }
int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx; AVPacket pkt1, *packet = &pkt1; int video_index = -1; int audio_index = -1; int i; is->videoStream=-1; is->audioStream=-1; global_video_state = is; // will interrupt blocking functions if we quit! url_set_interrupt_cb(decode_interrupt_cb); // Open video file if(av_open_input_file(&pFormatCtx, is->filename, NULL, 0, NULL)!=0) return -1; // Couldn't open file is->pFormatCtx = pFormatCtx; // Retrieve stream information if(av_find_stream_info(pFormatCtx)<0) return -1; // Couldn't find stream information // Dump information about file onto standard error dump_format(pFormatCtx, 0, is->filename, 0); // Find the first video stream for(i=0; i<pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO && video_index < 0) { video_index=i; } if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO && audio_index < 0) { audio_index=i; } } if(audio_index >= 0) { stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } if(is->videoStream < 0 || is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } // main decode loop for(;;) { if(is->quit) { break; } // seek stuff goes here if(is->seek_req) { int stream_index= -1; int64_t seek_target = is->seek_pos; if (is->videoStream >= 0) stream_index = is->videoStream; else if(is->audioStream >= 0) stream_index = is->audioStream; if(stream_index>=0){ seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q, pFormatCtx->streams[stream_index]->time_base); } if(!av_seek_frame(is->pFormatCtx, stream_index, seek_target, is->seek_flags)) { fprintf(stderr, "%s: error while seeking\n", is->pFormatCtx->filename); } else { if(is->audioStream >= 0) { packet_queue_flush(&is->audioq); packet_queue_put(&is->audioq, &flush_pkt); } if(is->videoStream >= 0) { packet_queue_flush(&is->videoq); packet_queue_put(&is->videoq, &flush_pkt); } } is->seek_req = 0; } 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(url_ferror(&pFormatCtx->pb) == 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); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while(!is->quit) { SDL_Delay(100); } fail: { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; }
int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx = avformat_alloc_context (); AVPacket pkt1, *packet = &pkt1; int video_index = -1; int audio_index = -1; int i; is->videoStream=-1; is->audioStream=-1; is->quit = 0; Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton ().openResource (is->resourceName); if(stream.isNull ()) throw std::runtime_error("Failed to open video resource"); is->stream = stream; AVIOContext *ioContext = 0; ioContext = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); if (!ioContext) throw std::runtime_error("Failed to allocate ioContext "); pFormatCtx->pb = ioContext; global_video_state = is; // will interrupt blocking functions if we quit! //url_set_interrupt_cb(decode_interrupt_cb); // Open video file /// \todo leak here, ffmpeg or valgrind bug ? if (avformat_open_input(&pFormatCtx, is->resourceName.c_str(), NULL, NULL)) throw std::runtime_error("Failed to open video input"); // Retrieve stream information if(avformat_find_stream_info(pFormatCtx, NULL)<0) throw std::runtime_error("Failed to retrieve stream information"); // Dump information about file onto standard error av_dump_format(pFormatCtx, 0, is->resourceName.c_str(), 0); for(i=0; i < (int)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) { stream_component_open(is, audio_index, pFormatCtx); } if(video_index >= 0) { stream_component_open(is, video_index, pFormatCtx); } if(is->videoStream >= 0 /*|| is->audioStream < 0*/) { // main decode loop for(;;) { if(is->quit) { break; } if( (is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || is->videoq.size > MAX_VIDEOQ_SIZE) { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); continue; } if(av_read_frame(pFormatCtx, packet) < 0) { break; } // Is this a packet from the video stream? if(packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while(!is->quit) { // EOF reached, all packets processed, we can exit now if (is->audioq.nb_packets == 0 && is->videoq.nb_packets == 0) break; boost::this_thread::sleep(boost::posix_time::milliseconds(100)); } } is->quit = 1; is->audioq.cond.notify_one(); is->videoq.cond.notify_one(); if (is->video_thread.joinable()) is->video_thread.join(); if (is->audioStream >= 0) avcodec_close(is->audio_st->codec); if (is->videoStream >= 0) avcodec_close(is->video_st->codec); sws_freeContext (is->sws_context); avformat_close_input(&pFormatCtx); pFormatCtx = NULL; av_free(ioContext); return 0; }
void *decode_thread(void *arg) { //fprintf(stdout, "[FFmpeg-main thread] decode_thread created\n"); VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx = NULL; AVPacket pkt1, *packet = &pkt1; AVIOInterruptCB callback; int video_index = -1; int i; is->videoStream=-1; // Will interrupt blocking functions ifwe quit! callback.callback = decode_interrupt_cb; callback.opaque = is; fprintf(stdout, "[FFmpeg-decode thread] Try to open I/O\n"); if(avio_open2(&is->io_context, is->filename, 0, &callback, NULL) < 0) { fprintf(stdout, "Unable to open I/O for file\n"); return NULL; } //fprintf(stdout, "avio_open2 done\n"); // Open video file fprintf(stdout, "[FFmpeg-decode thread] Try to open format context\n"); if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL)!=0) { fprintf(stdout, "Couldn't Open file\n"); return NULL; // Couldn't open file } //fprintf(stdout, "open_input done\n"); is->pFormatCtx = pFormatCtx; // Retrieve stream information fprintf(stdout, "[FFmpeg-decode thread] Try to Retrieve stream info\n"); if(avformat_find_stream_info(pFormatCtx, NULL)<0) { fprintf(stdout, "Couldn't Retrieve stream information\n"); return NULL; // Couldn't find stream information } // Dump information about file onto standard error av_dump_format(pFormatCtx, 0, is->filename, 0); // Find the first video stream for(i=0; i<pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index=i; break; } } if(video_index == -1) { fprintf(stdout, "Couldn't find video stream\n"); return NULL; } //fprintf(stdout, "stream component open\n"); stream_component_open(is, video_index); // main decode loop //fprintf(stdout, "[FFmpeg-decode thread] read frame\n"); for(;;) { if(is->quit) { break; } if(av_read_frame(is->pFormatCtx, packet) < 0) { if(is->pFormatCtx->pb->error == 0) continue; else break; } if(packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); //fprintf(stdout, "packs ready to load: %d\n",is->videoq.nb_packets); } else av_free_packet(packet); } fprintf(stdout, "[FFmpeg-decode thread] thread terminated\n"); return NULL; }
int decode_thread(void *arg){ VideoState *is = (VideoState *) arg; AVFormatContext *pFormatCtx = NULL; AVPacket pkt1, *packet = &pkt1; int video_index = -1; int audio_index = -1; int i; is->videoStream = -1; is->audioStream = -1; AVDictionary *io_dic = NULL; AVIOInterruptCB interupt_cb; //global_video_state = is; interupt_cb.callback = decode_interrupt_cb; // will interrupt blocking functions if we quit! interupt_cb.opaque = is; if (avio_open2(&is->io_ctx, is->filename, 0, &interupt_cb, &io_dic)){ fprintf(stderr, "Cannot open I/O for %s\n", is->filename); return -1; } // Open video file if (avformat_open_input(&pFormatCtx, is->filename, NULL, NULL) != 0){ return -1; // Couldn't open file } is->pFormatCtx = pFormatCtx; // Retrieve stream information if (avformat_find_stream_info(pFormatCtx, NULL) < 0){ return -1; // Couldn't find stream information } av_dump_format(pFormatCtx, 0, is->filename, 0); // Dump information about file onto standard error // Find the first video stream 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){ stream_component_open(is, audio_index); } if (video_index >= 0){ stream_component_open(is, video_index); } if (is->videoStream < 0 || is->audioStream < 0){ fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } // main decode loop for (;;) { if (is->quit){ break; } // seek stuff goes here if(is->seek_req){ int str_index = -1; int64_t seek_trgt = is->seek_pos; if (is->videoStream >= 0 ){ str_index = is->videoStream; }else if (is->audioStream >= 0){ str_index = is->audioStream; } if (str_index >= 0){ seek_trgt = av_rescale_q(seek_trgt, AV_TIME_BASE_Q, pFormatCtx->streams[str_index]->time_base); } if(av_seek_frame(is->pFormatCtx, str_index, seek_trgt, is->seek_flag) < 0 ){ fprintf(stderr , "%s : seeking error\n", is->pFormatCtx->filename); }else{ if (is->audioStream >= 0){ packet_queue_f(&is->audioq); packet_queue_put(&is->audioq,&f_pkt); } if (is->videoStream >= 0){ packet_queue_f(&is->videoq); packet_queue_put(&is->videoq,&f_pkt); } } is->seek_req = 0 ; } /*if (is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_VIDEOQ_SIZE){ SDL_Delay(10); continue; } // !!!! maybe need to remove this func !!! ^^^*/ 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); } else if (packet->stream_index == is->audioStream){ packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while (!is->quit) { SDL_Delay(100); } fail:{ SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; }
int player_prepare(State **ps, int from_thread) { int audio_index = -1; int video_index = -1; int i; State *state = *ps; if (state && state->pFormatCtx) { avformat_close_input(&state->pFormatCtx); } state->pFormatCtx = NULL; state->audio_stream = -1; state->video_stream = -1; state->audio_st = NULL; state->video_st = NULL; printf("Path: %s\n", state->filename); AVDictionary *options = NULL; av_dict_set(&options, "user-agent", "FFmpegMediaPlayer", 0); if (avformat_open_input(&state->pFormatCtx, state->filename, NULL, &options) != 0) { printf("Input file could not be opened\n"); *ps = NULL; return FAILURE; } if (avformat_find_stream_info(state->pFormatCtx, NULL) < 0) { printf("Stream information could not be retrieved\n"); avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; } char duration[30] = "0"; get_duration(state->pFormatCtx, duration); av_dict_set(&state->pFormatCtx->metadata, DURATION, duration, 0); // Find the first audio and video stream for (i = 0; i < state->pFormatCtx->nb_streams; i++) { if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index = i; } if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) { audio_index = i; } set_codec(state->pFormatCtx, i); } if (audio_index >= 0) { stream_component_open(state, audio_index, from_thread); } if (video_index >= 0) { stream_component_open(state, video_index, from_thread); } if (state->video_stream < 0 && state->audio_stream < 0) { avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; } state->pFormatCtx->interrupt_callback.callback = decode_interrupt_cb; state->pFormatCtx->interrupt_callback.opaque = state; // fill the inital buffer AVPacket packet; memset(&packet, 0, sizeof(packet)); //make sure we can safely free it int j, ret; int bytes_written = 0; while (bytes_written < state->buffer_size) { for (j = 0; j < state->pFormatCtx->nb_streams; j++) { //av_init_packet(&packet); ret = av_read_frame(state->pFormatCtx, &packet); if (ret < 0) { if (ret == AVERROR_EOF || url_feof(state->pFormatCtx->pb)) { //break; } } int frame_size_ptr = 0; ret = decode_frame_from_packet(state, &packet, &frame_size_ptr, from_thread); __android_log_print(ANDROID_LOG_ERROR, "TAG", "Fill buffer: %d -> %d", frame_size_ptr, state->buffer_size); bytes_written = bytes_written + frame_size_ptr; av_free_packet(&packet); } } *ps = state; state->notify_callback(state->clazz, MEDIA_PREPARED, 0, 0, from_thread); return SUCCESS; }
int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVFormatContext *pFormatCtx = NULL; AVPacket pkt1, *packet = &pkt1; AVDictionary *io_dict = NULL; AVIOInterruptCB callback; int video_index = -1; int audio_index = -1; int i; is->videoStream = -1; is->audioStream = -1; is->audio_need_resample = 0; global_video_state = is; // will interrupt blocking functions if we quit! callback.callback = decode_interrupt_cb; callback.opaque = is; if(avio_open2(&is->io_context, is->filename, 0, &callback, &io_dict)) { fprintf(stderr, "Unable to open I/O for %s\n", is->filename); return -1; } // Open video file if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL) != 0) { return -1; // Couldn't open file } is->pFormatCtx = pFormatCtx; // Retrieve stream information if(avformat_find_stream_info(pFormatCtx, NULL) < 0) { return -1; // Couldn't find stream information } // Dump information about file onto standard error av_dump_format(pFormatCtx, 0, is->filename, 0); // Find the first video stream 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) { stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } if(is->videoStream < 0 && is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } #ifdef __RESAMPLER__ if( audio_index >= 0 && pFormatCtx->streams[audio_index]->codec->sample_fmt != AV_SAMPLE_FMT_S16) { is->audio_need_resample = 1; is->pResampledOut = NULL; is->pSwrCtx = NULL; printf("Configure resampler: "); #ifdef __LIBAVRESAMPLE__ printf("libAvResample\n"); is->pSwrCtx = avresample_alloc_context(); #endif #ifdef __LIBSWRESAMPLE__ printf("libSwResample\n"); is->pSwrCtx = swr_alloc(); #endif // Some MP3/WAV don't tell this so make assumtion that // They are stereo not 5.1 if (pFormatCtx->streams[audio_index]->codec->channel_layout == 0 && pFormatCtx->streams[audio_index]->codec->channels == 2) { pFormatCtx->streams[audio_index]->codec->channel_layout = AV_CH_LAYOUT_STEREO; } else if (pFormatCtx->streams[audio_index]->codec->channel_layout == 0 && pFormatCtx->streams[audio_index]->codec->channels == 1) { pFormatCtx->streams[audio_index]->codec->channel_layout = AV_CH_LAYOUT_MONO; } else if (pFormatCtx->streams[audio_index]->codec->channel_layout == 0 && pFormatCtx->streams[audio_index]->codec->channels == 0) { pFormatCtx->streams[audio_index]->codec->channel_layout = AV_CH_LAYOUT_STEREO; pFormatCtx->streams[audio_index]->codec->channels = 2; } av_opt_set_int(is->pSwrCtx, "in_channel_layout", pFormatCtx->streams[audio_index]->codec->channel_layout, 0); av_opt_set_int(is->pSwrCtx, "in_sample_fmt", pFormatCtx->streams[audio_index]->codec->sample_fmt, 0); av_opt_set_int(is->pSwrCtx, "in_sample_rate", pFormatCtx->streams[audio_index]->codec->sample_rate, 0); av_opt_set_int(is->pSwrCtx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); av_opt_set_int(is->pSwrCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int(is->pSwrCtx, "out_sample_rate", 44100, 0); #ifdef __LIBAVRESAMPLE__ if (avresample_open(is->pSwrCtx) < 0) { #else if (swr_init(is->pSwrCtx) < 0) { #endif fprintf(stderr, " ERROR!! From Samplert: %d Hz Sample format: %s\n", pFormatCtx->streams[audio_index]->codec->sample_rate, av_get_sample_fmt_name(pFormatCtx->streams[audio_index]->codec->sample_fmt)); fprintf(stderr, " To 44100 Sample format: s16\n"); is->audio_need_resample = 0; is->pSwrCtx = NULL;; } } #endif // main decode loop for(;;) { if(is->quit) { 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); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } } /* all done - wait for it */ while(!is->quit) { SDL_Delay(100); } fail: { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; } const char g_szClassName[] = "myWindowClass"; // Step 4: the Window Procedure LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } sem_t mutex; HWND hwnd; static void * window_manager(void * data) { printf("Window manager has been started!\n"); WNDCLASSEX wc; MSG Msg; //Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; //wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } // Step 2: Creating the Window hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, "The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, NULL, NULL); sem_post(&mutex); if(hwnd == NULL) { MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } else { printf("window hwnd = %d\n", hwnd); } ShowWindow(hwnd, TRUE); UpdateWindow(hwnd); // Step 3: The Message Loop while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }
int decode_thread(void* arg) { // CoInitialize(NULL); CoInitializeEx(NULL, COINIT_MULTITHREADED); printf("decode_thread\n"); VideoState* is = (VideoState*) arg; AVFormatContext* pFormatCtx; AVPacket pkt1, *packet = &pkt1; int video_index = -1; int audio_index = -1; int i; global_video_state = is; if (avformat_open_input(&pFormatCtx, is->filename, NULL, NULL) != 0) { return -1; } is->pFormatCtx = pFormatCtx; if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { return -1; } av_dump_format(pFormatCtx, 0, is->filename, 0); 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) stream_component_open(is, audio_index); if (video_index >= 0) stream_component_open(is, video_index); if (is->videoStream < 0 || is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } // main decode loop for (;;) { if (is->quit) { SDL_LockMutex(is->audioq.mutex); SDL_CondSignal(is->audioq.cond); SDL_UnlockMutex(is->audioq.mutex); break; } //seek stuff goes here if (is->seek_req) { int stream_index = -1; int64_t seek_target = is->seek_pos; if (is->videoStream >= 0) stream_index = is->videoStream; else if (is->audioStream >= 0) stream_index = is->audioStream; if (stream_index >= 0) { seek_target = av_rescale_q(seek_target, AV_TIME_BASE_Q, pFormatCtx->streams[stream_index]->time_base); } if (av_seek_frame(is->pFormatCtx, stream_index, seek_target, is->seek_flags) < 0) { fprintf(stderr, "%s: error while seeking\n", is->pFormatCtx->filename); } else { if (is->audioStream >= 0) { packet_queue_flush(&is->audioq); packet_queue_put(&is->audioq, &flush_pkt, 0); } } is->seek_req = 0; } if (is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_AUDIOQ_SIZE) { SDL_Delay(10); continue; } if (av_read_frame(is->pFormatCtx, packet) < 0) { printf("av_read_frame\n"); fflush(stdout); if (is->pFormatCtx->pb->error == 0) { SDL_Delay(100); // no error, wait for user input continue; } else { break; } } if (packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet, 1); } else if (packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet, 0); } else { av_free_packet(packet); } } // all done - wait for it while (!is->quit) { SDL_Delay(100); } fail: if (1) { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; }
int decode_thread( void *thread_arg ) { VideoState *is = (VideoState *) thread_arg; AVFormatContext *pFormatCtx; AVPacket pkt1, *packet = &pkt1; //global_video_state = is; url_set_interrupt_cb(decode_interrupt_cb); // will interrupt blocking functions if we quit! // is->filename[0] = *"./foo.mkv"; strcpy(is->filename, "./foo.mkv"); int i; //AVCodecContext *pCodecCtx; //AVCodecContext *aCodecCtx; // Open video file if( av_open_input_file(&pFormatCtx, is->filename, NULL, 0, NULL) != 0 ) return -1; // Couldn't open file is->pFormatCtx = pFormatCtx; // Retrieve stream information if(av_find_stream_info(pFormatCtx)<0) return -1; // Couldn't find stream information // Dump information about file onto standard error //dump_format(pFormatCtx, 0, is->filename, 0); // Find the video stream and audio stream int videoStream = -1; int audioStream = -1; is->videoStream = -1; is->audioStream = -1; for( i=0; i<pFormatCtx->nb_streams; i++ ) { if( pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) { videoStream = i; } if( pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO && audioStream < 0 ) { audioStream = i; } } if(videoStream == -1) return -1; // Didn't find a video stream if(audioStream == -1) printf( "No audio stream\n" ); else stream_component_open( is, audioStream ); stream_component_open( is, videoStream ); if(is->videoStream < 0 ) { fprintf(stderr, "%s: could not open codecs\n", is->filename); goto fail; } // Decode loop for(;;) { if(is->quit) { break; } 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( url_ferror((ByteIOContext *)&pFormatCtx->pb) == 0 ) { SDL_Delay(100); // no error; wait for user input continue; } else { break; } } // Queue the packets into the right queue if(packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); } else if(packet->stream_index == is->audioStream) { packet_queue_put(&is->audioq, packet); } else { av_free_packet(packet); } */ } while(!is->quit) { SDL_Delay(100); } fail: if(1){ SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); } return 0; } // End decode_thread()
static int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVFormatContext *ic = NULL; AVPacket pkt1, *packet = &pkt1; int ret, i; int video_index = -1; is->videoStream = -1; global_video_state = is; if (avformat_open_input(&ic, is->filename, NULL, NULL) != 0) { return -1; } /* 这个回调函数将赋值给AVFormatContex,这样当读取流出现问题的时候会调用我们的自己的处理 */ static const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL }; ic->interrupt_callback = int_cb; is->ic = ic; is->external_clock_base = 0; is->external_clock_base = get_external_clock(is); if (avformat_find_stream_info(ic, NULL) < 0) { return -1; } av_dump_format(ic, 0, is->filename, 0); for(i=0; i<ic->nb_streams; i++) { if(ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) video_index = i; } if(video_index >= 0) stream_component_open(is, video_index); /* 开始解码主循环 */ for(;;) { if(is->quit) break; /* 这里处理视频的快进和快退 */ if(is->seek_req) { int stream_index = -1; int64_t seek_target = is->seek_pos; is->external_clock_base = 0; is->external_clock_base = get_external_clock(is) - (seek_target / 1000000.0); if(is->videoStream >= 0) stream_index = is->videoStream; /* av_rescale_q(a, b, c):通过计算a*b/c来把一个时间基调整到另一个时间基 */ /* 使用这个函数的原因是可以防止计算溢出,AV_TIME_BASE_Q是AV_TIME_BASE作*/ /* 为分母的版本 */ if(stream_index >= 0) seek_target = av_rescale_q(seek_target, AV_TIME_BASE_Q , ic->streams[stream_index]->time_base); if(av_seek_frame(is->ic, stream_index, seek_target, is->seek_flags) < 0) { fprintf(stderr, "%d: %s error seek\n", __LINE__, is->filename); } else { /* 跳转后需要清空我们自己的缓冲队列和avcodec内部缓冲*/ /* 然后放入一个用来标识刷新队列的标志包 */ if(is->videoStream >= 0) { packet_queue_flush(&is->videoq); packet_queue_put(&is->videoq, &flush_pkt); } } is->seek_req = 0; } //printf("decode_thread loop check videoq size %d\n", is->videoq.size); if (is->videoq.size > MAX_VIDEOQ_SIZE) { //printf("decode_thread loop delay %d\n", is->videoq.size); SDLMOD_Delay(10); continue; } ret = av_read_frame(is->ic, packet); if (ret < 0) { if(ret == AVERROR_EOF || url_feof(is->ic->pb)) { break; } if(is->ic->pb && is->ic->pb->error) { break; } continue; } if(packet->stream_index == is->videoStream) { packet_queue_put(&is->videoq, packet); } else { av_free_packet(packet); } //printf("decode_thread loop %d\n", is->videoq.size); } printf("decode_thread loop wait start\n"); save_bmp(); while (!is->quit && is->videoq.size > 0) { //printf("decode_thread delay %d\n", is->videoq.size); SDLMOD_Delay(100); } fail: { SDLMOD_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDLMOD_PushEvent(&event); printf("push FF_QUIT_EVENT\n"); } return 0; }
int set_data_source_l(State **ps, const char* path) { printf("set_data_source\n"); int audio_index = -1; int video_index = -1; int i; State *state = *ps; printf("Path: %s\n", path); AVDictionary *options = NULL; av_dict_set(&options, "icy", "1", 0); av_dict_set(&options, "user-agent", "FFmpegMediaMetadataRetriever", 0); if (state->headers) { av_dict_set(&options, "headers", state->headers, 0); } if (state->offset > 0) { state->pFormatCtx = avformat_alloc_context(); state->pFormatCtx->skip_initial_bytes = state->offset; } if (avformat_open_input(&state->pFormatCtx, path, NULL, &options) != 0) { printf("Metadata could not be retrieved\n"); *ps = NULL; return FAILURE; } if (avformat_find_stream_info(state->pFormatCtx, NULL) < 0) { printf("Metadata could not be retrieved\n"); avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; } set_duration(state->pFormatCtx); set_shoutcast_metadata(state->pFormatCtx); //av_dump_format(state->pFormatCtx, 0, path, 0); // Find the first audio and video stream for (i = 0; i < state->pFormatCtx->nb_streams; i++) { if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index = i; } if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) { audio_index = i; } set_codec(state->pFormatCtx, i); } if (audio_index >= 0) { stream_component_open(state, audio_index); } if (video_index >= 0) { stream_component_open(state, video_index); } /*if(state->video_stream < 0 || state->audio_stream < 0) { avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; }*/ set_rotation(state->pFormatCtx, state->audio_st, state->video_st); set_framerate(state->pFormatCtx, state->audio_st, state->video_st); set_filesize(state->pFormatCtx); set_chapter_count(state->pFormatCtx); /*printf("Found metadata\n"); AVDictionaryEntry *tag = NULL; while ((tag = av_dict_get(state->pFormatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { printf("Key %s: \n", tag->key); printf("Value %s: \n", tag->value); }*/ *ps = state; return SUCCESS; }
int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; AVPacket pkt1, *packet = &pkt1; AVDictionary *io_dict = NULL; AVIOInterruptCB callback; int video_index = -1; int audio_index = -1; int i; int ret; int eof = 0; is->videoStream=-1; is->audioStream=-1; AVDictionary *options = NULL; av_dict_set(&options, "icy", "1", 0); av_dict_set(&options, "user-agent", "FFmpegMediaPlayer", 0); if (is->headers) { av_dict_set(&options, "headers", is->headers, 0); } if (is->offset > 0) { is->pFormatCtx = avformat_alloc_context(); is->pFormatCtx->skip_initial_bytes = is->offset; //is->pFormatCtx->iformat = av_find_input_format("mp3"); } // will interrupt blocking functions if we quit! callback.callback = decode_interrupt_cb; callback.opaque = is; if (avio_open2(&is->io_context, is->filename, 0, &callback, &io_dict)) { fprintf(stderr, "Unable to open I/O for %s\n", is->filename); return -1; } // Open video file if(avformat_open_input(&is->pFormatCtx, is->filename, NULL, &options)!=0) return -1; // Couldn't open file // Retrieve stream information if(avformat_find_stream_info(is->pFormatCtx, NULL)<0) return -1; // Couldn't find stream information // Dump information about file onto standard error av_dump_format(is->pFormatCtx, 0, is->filename, 0); // Find the first video stream for(i=0; i<is->pFormatCtx->nb_streams; i++) { if(is->pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index=i; } if(is->pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && audio_index < 0) { audio_index=i; } set_codec(is->pFormatCtx, i); } if(audio_index >= 0) { stream_component_open(is, audio_index); } if(video_index >= 0) { stream_component_open(is, video_index); } if(is->videoStream < 0 && is->audioStream < 0) { //if(is->videoStream < 0 || is->audioStream < 0) { fprintf(stderr, "%s: could not open codecs\n", is->filename); notify(is, MEDIA_ERROR, 0, 0); return 0; } set_rotation(is->pFormatCtx, is->audio_st, is->video_st); set_framerate(is->pFormatCtx, is->audio_st, is->video_st); set_filesize(is->pFormatCtx); set_chapter_count(is->pFormatCtx); // main decode loop for(;;) { if(is->quit) { break; } /*if (is->paused != is->last_paused) { is->last_paused = is->paused; if (is->paused) is->read_pause_return = av_read_pause(is->pFormatCtx); else av_read_play(is->pFormatCtx); }*/ // seek stuff goes here if(is->seek_req) { int64_t seek_target = is->seek_pos; int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN; int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX; int ret = avformat_seek_file(is->pFormatCtx, -1, seek_min, seek_target, seek_max, is->seek_flags); if(ret < 0) { fprintf(stderr, "%s: error while seeking\n", is->pFormatCtx->filename); } else { if(is->audioStream >= 0) { packet_queue_flush(&is->audioq); packet_queue_put(is, &is->audioq, &is->flush_pkt); } if(is->videoStream >= 0) { packet_queue_flush(&is->videoq); packet_queue_put(is, &is->videoq, &is->flush_pkt); } notify(is, MEDIA_SEEK_COMPLETE, 0, 0); } is->seek_req = 0; eof = 0; } if (is->audioq.size >= MAX_AUDIOQ_SIZE && !is->prepared) { queueAudioSamples(&is->audio_player, is); notify(is, MEDIA_PREPARED, 0, 0); is->prepared = 1; } if(is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_VIDEOQ_SIZE) { SDL_Delay(10); continue; } if((ret = av_read_frame(is->pFormatCtx, packet)) < 0) { if (ret == AVERROR_EOF || !is->pFormatCtx->pb->eof_reached) { eof = 1; break; } 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, &is->videoq, packet); } else if(packet->stream_index == is->audioStream) { packet_queue_put(is, &is->audioq, packet); } else { av_free_packet(packet); } if (eof) { break; } } if (eof) { notify(is, MEDIA_PLAYBACK_COMPLETE, 0, 0); } return 0; }
static int read_thread(void *arg) { VideoState *is = (VideoState*)arg; AVFormatContext *ic = NULL; int i; int st_index[AVMEDIA_TYPE_NB]; // 讲解一下 AVPacket pkt1, *pkt = &pkt1; memset(st_index, -1, sizeof(st_index)); ic = avformat_alloc_context(); avformat_open_input(&ic, is->filename, NULL, NULL); is->ic = ic; avformat_find_stream_info(ic, NULL); for (i = 0; i<ic->nb_streams; i++) { if (ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) st_index[AVMEDIA_TYPE_VIDEO] = i; if (ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) st_index[AVMEDIA_TYPE_AUDIO] = i; } /* open the streams,并开启相应的解码线程 */ if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) { stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]); } if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]); } if (is->video_stream < 0 && is->audio_stream < 0) { av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n", is->filename); goto fail; } for (;;) { /* if the queue are full, no need to read more */ // 暂时把以下这个判断注掉,不限制packet queue的大小 // 不然的话,可能因为视频消耗packet比较慢(比如我们强制41ms刷新一次),导致视频queue超过max // 此时如果不再读包,会导致音频没包可解,听起来就是杂音 /* if (is->audioq.size > MAX_AUDIOQ_SIZE || is->videoq.size > MAX_VIDEOQ_SIZE) { SDL_Delay(10); continue; } */ if (av_read_frame(ic, pkt) < 0) { //break; } if (pkt->stream_index == is->audio_stream) { packet_queue_put(&is->audioq, pkt); } else if (pkt->stream_index == is->video_stream) { packet_queue_put(&is->videoq, pkt); } else { av_free_packet(pkt); } } fail: /* close each stream */ // TODO close streams if (ic) { avformat_close_input(&ic); is->ic = NULL; } SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); return 0; }
int set_data_source(State **ps, const char* path) { printf("set_data_source\n"); int audio_index = -1; int video_index = -1; int i; State *state = *ps; if (state && state->pFormatCtx) { avformat_close_input(&state->pFormatCtx); } if (!state) { state = av_mallocz(sizeof(State)); } state->pFormatCtx = NULL; state->audio_stream = -1; state->video_stream = -1; state->audio_st = NULL; state->video_st = NULL; char duration[30] = "0"; printf("Path: %s\n", path); AVDictionary *options = NULL; av_dict_set(&options, "icy", "1", 0); av_dict_set(&options, "user-agent", "FFmpegMediaMetadataRetriever", 0); if (avformat_open_input(&state->pFormatCtx, path, NULL, &options) != 0) { printf("Metadata could not be retrieved\n"); *ps = NULL; return FAILURE; } if (avformat_find_stream_info(state->pFormatCtx, NULL) < 0) { printf("Metadata could not be retrieved\n"); avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; } get_duration(state->pFormatCtx, duration); av_dict_set(&state->pFormatCtx->metadata, DURATION, duration, 0); get_shoutcast_metadata(state->pFormatCtx); //av_dump_format(state->pFormatCtx, 0, path, 0); // Find the first audio and video stream for (i = 0; i < state->pFormatCtx->nb_streams; i++) { if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index = i; } if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) { audio_index = i; } set_codec(state->pFormatCtx, i); } /*if (audio_index >= 0) { stream_component_open(state, audio_index); }*/ if (video_index >= 0) { stream_component_open(state, video_index); } /*if(state->video_stream < 0 || state->audio_stream < 0) { avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; }*/ /*printf("Found metadata\n"); AVDictionaryEntry *tag = NULL; while ((tag = av_dict_get(state->pFormatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { printf("Key %s: \n", tag->key); printf("Value %s: \n", tag->value); }*/ *ps = state; return SUCCESS; }