ffmpeg 簡單播放器
阿新 • • 發佈:2019-01-01
#include <unistd.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswresample/swresample.h> #include <libswscale/swscale.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h> #include <libavutil/samplefmt.h>
struct AVContext{ AVFormatContext* fc; AVCodecContext* acc; AVCodecContext* vcc; int audio_index; int video_index;
struct SwsContext* sws; struct SwrContext* swr;
SDL_Surface* wnd; SDL_Overlay* overlay;
SDL_AudioSpec audio_spec; int width; int height;
int fdRead; int fdWrite;
AVPacket* packet; AVFrame* audio_frame; AVFrame* video_frame; };
struct AVContext avc;
int doWrite(int fd, uint8_t* buf, int len) { int index = 0; while (index != len) { int ret = write(fd, buf + index, len - index); if (ret > 0) index += ret; else if (ret <= 0) return -1; } return 0; }
int doRead(int fd, uint8_t* buf, int len) { int index = 0; while (index != len) { int ret = read(fd, buf + index, len - index); if (ret > 0) index += ret; else if (ret <= 0) return -1; } }
void open_avfile(const char* filename) { if (NULL == filename) { return; } avc.fc = NULL; if (avformat_open_input(&avc.fc, filename, NULL, NULL) != 0) { printf("open error\n"); exit(1); } }
void find_stream_info() { avc.audio_index = -1; avc.video_index = -1; if (avformat_find_stream_info(avc.fc, NULL) != 0) { printf("find stream info error\n"); exit(1); } int i; for (i = 0; i < avc.fc->nb_streams; ++i) { if (avc.fc->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { avc.audio_index = i; } else if (avc.fc->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { avc.video_index = i; } } if (avc.audio_index == -1 || avc.video_index == -1) { printf("cannot find audio or video stream info err\n"); exit(1); } }
void open_codec_context() { avc.acc = NULL; avc.vcc = NULL; // video avc.vcc = avc.fc->streams[avc.video_index]->codec; avc.fc->video_codec = avcodec_find_decoder(avc.vcc->codec_id); if (avcodec_open2(avc.vcc, avc.fc->video_codec, NULL) != 0) { printf("open video codec err\n"); }
// audio avc.acc = avc.fc->streams[avc.audio_index]->codec; avc.fc->audio_codec = avcodec_find_decoder(avc.acc->codec_id); if (avcodec_open2(avc.acc, avc.fc->audio_codec, NULL) != 0) { printf("open audio codec err\n"); } }
void init_convert_context() { avc.sws = NULL; avc.swr = NULL;
avc.sws = sws_getContext(avc.vcc->width, avc.vcc->height, avc.vcc->pix_fmt, avc.vcc->width, avc.vcc->height, avc.vcc->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
avc.swr = swr_alloc_set_opts(NULL, avc.acc->channel_layout, AV_SAMPLE_FMT_S16, avc.acc->sample_rate, avc.acc->channel_layout, avc.acc->sample_fmt, avc.acc->sample_rate, 0, NULL);
swr_init(avc.swr); }
void audio_callback(void* userdata, Uint8* stream, int len) { doRead(avc.fdRead, stream, len); }
void init_sdl() { avc.width = avc.vcc->width; avc.height = avc.vcc->height;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) { printf("sdl init error\n"); exit(1); }
avc.wnd = SDL_SetVideoMode(avc.width, avc.height, 0, 0);
if (avc.wnd == NULL) { printf("create window error\n"); exit(1); }
avc.overlay = SDL_CreateYUVOverlay(avc.width, avc.height, SDL_YV12_OVERLAY , avc.wnd); if (avc.overlay == NULL) { printf("create overlay error\n"); exit(1); }
// audio play avc.audio_spec.callback = audio_callback; avc.audio_spec.channels = avc.acc->channels; avc.audio_spec.format = AUDIO_S16SYS; avc.audio_spec.freq = avc.acc->sample_rate; avc.audio_spec.samples = 1024; avc.audio_spec.silence = 0; avc.audio_spec.userdata = NULL; if (SDL_OpenAudio(&avc.audio_spec, NULL) != 0) { printf("sdl open audio error\n"); exit(1); } SDL_PauseAudio(0);
int fd[2]; pipe(fd);
void process_audio_data() { int got; avcodec_decode_audio4(avc.acc, avc.audio_frame, &got, avc.packet); if (got == 0) return;
int bytesPerSample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); int frameSize = avc.acc->frame_size * avc.acc->channels * bytesPerSample; uint8_t* data = (uint8_t*)malloc(frameSize);
swr_convert(avc.swr, &data, avc.acc->frame_size * 2, avc.audio_frame->extended_data, avc.acc->frame_size);
doWrite(avc.fdWrite, data, frameSize); free(data); }
void process_video_data() { int got; avcodec_decode_video2(avc.vcc, avc.video_frame, &got, avc.packet); if (got == 0) return; SDL_LockYUVOverlay(avc.overlay);
uint8_t* data[AV_NUM_DATA_POINTERS]; int linesize[AV_NUM_DATA_POINTERS];
data[0] = avc.overlay->pixels[0]; data[1] = avc.overlay->pixels[1]; data[2] = avc.overlay->pixels[2]; linesize[0] = avc.overlay->pitches[0]; linesize[1] = avc.overlay->pitches[1]; linesize[2] = avc.overlay->pitches[2];
sws_scale(avc.sws, avc.video_frame->data, avc.video_frame->linesize, 0, avc.vcc->height,data, linesize);
SDL_UnlockYUVOverlay(avc.overlay);
SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = avc.wnd->w; rect.h = avc.wnd->h; SDL_DisplayYUVOverlay(avc.overlay, &rect); }
void process_data() { avc.packet = av_packet_alloc(); avc.audio_frame = av_frame_alloc(); avc.video_frame = av_frame_alloc();
while (1) { if (av_read_frame(avc.fc, avc.packet) < 0) { break; } if (avc.packet->stream_index == avc.audio_index) { process_audio_data(); } else if (avc.packet->stream_index == avc.video_index) { process_video_data(); } } }
int main() { av_register_all();
open_avfile("/home/tuser/test/test.mp4");
find_stream_info();
open_codec_context();
init_convert_context();
init_sdl();
process_data();
return 0; }
Makefile:
play.out: play.c