1. 程式人生 > >ffmpeg 簡單播放器

ffmpeg 簡單播放器


#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);
// 為了簡便,用管道來控制每次讀取的資料     avc.fdRead = fd[0];     avc.fdWrite = fd[1]; }
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
gcc play.c -o play.out -pthread -lavdevice -lavfilter -lswscale -lpostproc -lavformat -lavcodec -lxcb-xfixes -lxcb-render -lxcb-shape -lxcb -lX11 -lasound -lSDL -lx264 -lpthread -ldl -lfaac -lz -lswresample -lavutil -lm