`
weiyuhu
  • 浏览: 235853 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

使用ffmpeg为库编写的小型多媒体播放器源代码

阅读更多
今天突发奇想,就在以前音频播放器(详细情况请看这里——http://blog.csdn.net/baymoon/archive/2006/11 /16/1388693.aspx)的基础上用ffmpeg写了个简单的多媒体播放器,这里把源代码贴出来,供大家参评;这里的多媒体播放,并没有用到什么很强大的音视频同步技术,而只是简单的使用了视频随着音频同步,想必你看了代码之后会有所悟的。。。不多说了,看代码。。。

/***************************************************************************
 *            main.cc
 *
 *  Thu Nov  9 20:47:33 2006
 *  Copyright  2006 
 *  Email lsosa.cs2c
 ****************************************************************************/


#include <avcodec.h>
#include <avformat.h>
#include <avutil.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <sys/soundcard.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sched.h>
#include <SDL/SDL.h>

#define ALL_DEBUG

#ifdef ALL_DEBUG
    #define AV_DEBUG
    #define AUDIO_DEBUG
#endif

//------------------------------------------------------------------------------
// manipulations for file
int open_file (char *file_name, int mode)
...{
    // open file file_name and return the file descriptor;
    int fd;

    if ((fd = open (file_name, mode)) < 0)
    ...{
        fprintf (stderr, " Can't open %s! ", file_name);
        exit (-1);
    }
    return fd;
}

int set_audio (int fd, AVCodecContext * pCodecCtx)
...{
    // set the properties of audio device with pCodecCtx;

    int i, err;
    /**//* 设置适当的参数,使得声音设备工作正常 */
    /**//* 详细情况请参考Linux关于声卡编程的文档 */
    
    i = 0;
    ioctl (fd, SNDCTL_DSP_RESET, &i);
    i = 0;
    ioctl (fd, SNDCTL_DSP_SYNC, &i);
    i = 1;
    ioctl (fd, SNDCTL_DSP_NONBLOCK, &i);
    
    // set sample rate;
    #ifdef AUDIO_DEBUG
    printf ("pCodecCtx->sample_rate:%d ", pCodecCtx->sample_rate);
    #endif
    i = pCodecCtx->sample_rate;
    if (ioctl (fd, SNDCTL_DSP_SPEED, &i) == -1)
    ...{
        fprintf (stderr, "Set speed to %d failed:%s ", i,
             strerror (errno));
        return (-1);
    }
    if (i != pCodecCtx->sample_rate)
    ...{
        fprintf (stderr, "do not support speed %d,supported is %d ",
             pCodecCtx->sample_rate, i);
        return (-1);
    }
    
    // set channels;
    i = pCodecCtx->channels;
    #ifdef AUDIO_DEBUG
    printf ("pCodecCtx->channels:%d ", pCodecCtx->channels);
    #endif
    if ((ioctl (fd, SNDCTL_DSP_CHANNELS, &i)) == -1)
    ...{
        fprintf (stderr, "Set Audio Channels %d failed:%s ", i,
             strerror (errno));
        return (-1);
    }
    if (i != pCodecCtx->channels)
    ...{
        fprintf (stderr, "do not support channel %d,supported %d ",
            pCodecCtx->channels, i);
        return (-1);
    }
    // set bit format;
    i = AFMT_S16_LE;
    if (ioctl (fd, SNDCTL_DSP_SETFMT, &i) == -1)
    ...{
        fprintf (stderr, "Set fmt to bit %d failed:%s ", i,
             strerror (errno));
        return (-1);
    }
    if (i != AFMT_S16_LE)
    ...{
        fprintf (stderr, "do not support bit %d, supported %d ",
             AFMT_S16_LE, i);
        return (-1);
    }
    
    // set application buffer size;
    // i = (0x00032 << 16) + 0x000c;        // 32 4kb buffer;
    // ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &i);
    i = 1;
    ioctl (fd, SNDCTL_DSP_PROFILE, &i);
    
    return 0;
}

void close_file (int fd)
...{
    // close the file pointed by file descriptor fd;
    close (fd);
}

//------------------------------------------------------------------------------
// handle audio;

void display_AVCodecContext(AVCodecContext *pCodecCtx)...{
    //
    #define STDOUT stderr
    fprintf(STDOUT, "pCodecCtx->bit_rate:%d ", pCodecCtx->bit_rate);
    fprintf(STDOUT, "pCodecCtx->sample_rate:%d ", pCodecCtx->sample_rate);
    fprintf(STDOUT, "pCodecCtx->channels:%d ", pCodecCtx->channels);
    fprintf(STDOUT, "pCodecCtx->frame_size:%d ", pCodecCtx->frame_size);
    fprintf(STDOUT, "pCodecCtx->frame_number:%d ", pCodecCtx->frame_number);
    fprintf(STDOUT, "pCodecCtx->delay:%d ", pCodecCtx->delay);
    fprintf(STDOUT, "pCodecCtx->frame_bits:%d ", pCodecCtx->frame_bits);
}

// error if return -1;
// success if return 0;
// 这里要用到指向指针的指针,否则传不到值;
int av_init (char *file_name, AVFormatContext ** pFormatCtx,
    AVCodecContext ** pAudioCodecCtx, int *p_audioStream, 
    AVCodecContext ** pVideoCodecCtx, int *p_videoStream)
...{
    // init the codec and format of input file file_name;
    int audioStream, i;
    int videoStream;
    AVCodec *pAudioCodec;
    AVCodec *pVideoCodec;
    // catch error
    assert(file_name != NULL);
    assert(*pFormatCtx != NULL);
    assert(*pAudioCodecCtx != NULL);
    
    // Register all formats and codecs
    av_register_all ();
    
    // open file
    if (av_open_input_file (pFormatCtx, file_name, NULL, 0, NULL) != 0)...{
        // Couldn't open file
        fprintf (stderr, " Can't open %s! ", file_name);
        return -1;    
    }

    // Retrieve stream information
    if (av_find_stream_info (*pFormatCtx) < 0)...{
        // Couldn't find stream information
        return -1;    
    }
    
    #ifdef AV_DEBUG
    // Dump information about file onto standard error
    dump_format (*pFormatCtx, 0, file_name, false);
    #endif
    
    // Find the first audio and video stream respectively
    audioStream = -1;
    videoStream = -1;
    for (i = 0; i < (*pFormatCtx)->nb_streams; i++)...{
        if ((*pFormatCtx)->streams[i]->codec->codec_type ==
            CODEC_TYPE_AUDIO)
        ...{
            audioStream = i;
        }else if ((*pFormatCtx)->streams[i]->codec->codec_type ==
            CODEC_TYPE_VIDEO)...{
            videoStream = i;
        }
    }
    
    #ifdef AV_DEBUG
    // dump_stream_info(pFormatCtx);
    #endif
    
    // exclude error
    if (audioStream == -1)...{
        // Didn't find a audio or video stream
        // return -1;    
        printf("No Audio ");
    }
    if (videoStream == -1)...{
        // Didn't find a audio or video stream
        // return -1;    
        printf("No Video ");
    }

    // Get a pointer to the codec context for the audio stream
    *pAudioCodecCtx = (*pFormatCtx)->streams[audioStream]->codec;
    *pVideoCodecCtx = (*pFormatCtx)->streams[videoStream]->codec;

    // Find the decoder for the audio stream
    pAudioCodec = avcodec_find_decoder ((*pAudioCodecCtx)->codec_id);
    pVideoCodec = avcodec_find_decoder ((*pVideoCodecCtx)->codec_id);
    // 
    if (pAudioCodec == NULL)...{
        return -1;    // Codec not found
    }
    if (pVideoCodec == NULL)...{
        return -1;    // Codec not found
    }

    // Open audio codec
    if (avcodec_open ((*pAudioCodecCtx), pAudioCodec) < 0)...{
        return -1;    // Could not open codec
    }
    // Open video codec
    if (avcodec_open ((*pVideoCodecCtx), pVideoCodec) < 0)...{
        return -1;    // Could not open codec
    }
    
    #ifdef AUDIO_DEBUG
    // printf ("pCodecCtx->sample_rate:%d, audioStream:%d ", (*pCodecCtx)->sample_rate, audioStream);
    // display_AVCodecContext(*pCodecCtx);
    #endif
    
    *p_audioStream = audioStream;
    *p_videoStream = videoStream;
    
    return 0;
}

void av_play (AVFormatContext * pFormatCtx,
    AVCodecContext * pAudioCodecCtx, int audioStream, 
    AVCodecContext * pVideoCodecCtx, int videoStream)
    // AVCodecContext * pCodecCtx, int audioStream)
...{
    // which was read from one frame;
    AVPacket packet;
    uint32_t len;
    uint8_t decompressed_audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    int decompressed_audio_buf_size;
    uint8_t * p_decompressed_audio_buf;
    int fd = -1;    // audio file or test file?
    char filename[64] = "/dev/dsp";
    int mode = O_WRONLY;
    // Video;
    AVFrame *pFrame;
    AVFrame *pFrameYUV;
    int frameFinished;
    
    /**////////// SDL initialization
    SDL_Surface *screen =
    SDL_SetVideoMode (pVideoCodecCtx->width, pVideoCodecCtx->height, 0, SDL_HWSURFACE);
    SDL_Overlay *overlay =
    SDL_CreateYUVOverlay (pVideoCodecCtx->width, pVideoCodecCtx->height,
              SDL_YV12_OVERLAY,
              screen);
    static SDL_Rect rect;
    rect.x = 0;
    rect.y = 0;
    rect.w = pVideoCodecCtx->width;
    rect.h = pVideoCodecCtx->height;
    /**///////////
    
    // open audio file or written file
    // printf("fd:%d", fd);
    fd = open_file(filename, mode);
    // printf("fd:%d", fd);
    // 
    set_audio(fd, pAudioCodecCtx);
    
    //
    printf("(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2=%d ", (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2);
    printf("AVCODEC_MAX_AUDIO_FRAME_SIZE=%d ", AVCODEC_MAX_AUDIO_FRAME_SIZE);
    
    // for a test
    // char test_file[256] = "my_pcm.pcm";
    // fd = open_file(test_file, mode);
    
    #ifdef AV_DEBUG
    static int size = 0;
    #endif
    //
    
    // set the sched priority
    // 这是为了提高音频优先级;不晓得起作用没;
    int policy = SCHED_FIFO;
    sched_setscheduler(0, policy, NULL);
    
    // Allocate video frame
    pFrame = avcodec_alloc_frame ();
    // Allocate an AVFrame structure
    pFrameYUV = avcodec_alloc_frame ();
    if (pFrameYUV == NULL)
        return;
    
    // Set SDL events
    SDL_EventState (SDL_ACTIVEEVENT, SDL_IGNORE);
    SDL_EventState (SDL_MOUSEMOTION, SDL_IGNORE);
    // SDL_ShowCursor (SDL_ENABLE);
    
    int write_buf_size = 4196;
    int written_size;
    while ((av_read_frame (pFormatCtx, &packet) >= 0)
        && (SDL_PollEvent (NULL) == 0))
    ...{
        // Is this a packet from the audio stream?
        // 判断是否音频帧;
        if (packet.stream_index == audioStream)
        ...{
            // Decode audio frame
            // 解码音频数据为pcm数据;
            len = avcodec_decode_audio (pAudioCodecCtx,  
                            (int16_t *)decompressed_audio_buf, 
                            &decompressed_audio_buf_size,        // it is the decompressed frame in BYTES 解码后的数据大小,字节为单位;
                            packet.data, 
                            packet.size );
            // printf("len:%d, packet.size:%d ", len, packet.size);
            // printf("packet.pts:%d packet.dts:%d ", packet.pts, packet.dts);
            if ( len < 0 )...{
                // if error len = -1
                printf("+----- error in decoding audio frame ");
                // exit(0);
            }
            // audio_buf_info info;
            p_decompressed_audio_buf = decompressed_audio_buf;
            while ( decompressed_audio_buf_size > 0 )...{
                // 解码后数据不为零,则播放之,为零,则;
                written_size = write(fd, p_decompressed_audio_buf, decompressed_audio_buf_size);
                if ( written_size == -1 )...{
                    // printf("error:decompressed_audio_buf_size:%d, decompressed_audio_buf_size:%d, %s ", 
                                decompressed_audio_buf_size, decompressed_audio_buf_size,strerror(errno));
                    // usleep(100);
                    continue;
                }
                // printf("decompressed_audio_buf_size:%d, written_size:%d ", 
                            decompressed_audio_buf_size, written_size);
                decompressed_audio_buf_size -= written_size;
                p_decompressed_audio_buf += written_size;
            }// end while
        }
        else if (packet.stream_index == videoStream)
        ...{
            // Decode video frame
            avcodec_decode_video (pVideoCodecCtx, pFrame, &frameFinished,
                    packet.data, packet.size);
            // Did we get a video frame?
            if (frameFinished) ...{
            // Convert the image from its native format to YUV, and display
            
            SDL_LockYUVOverlay (overlay);
            pFrameYUV->data[0] = overlay->pixels[0];
            pFrameYUV->data[1] = overlay->pixels[2];
            pFrameYUV->data[2] = overlay->pixels[1];
            
            pFrameYUV->linesize[0] = overlay->pitches[0];
            pFrameYUV->linesize[1] = overlay->pitches[2];
            pFrameYUV->linesize[2] = overlay->pitches[1];
            
            img_convert ((AVPicture *) pFrameYUV, PIX_FMT_YUV420P, 
                        (AVPicture *) pFrame, pVideoCodecCtx->pix_fmt, 
                        pVideoCodecCtx->width, pVideoCodecCtx->height);
            SDL_UnlockYUVOverlay (overlay);
            SDL_DisplayYUVOverlay (overlay, &rect);
            /**////
            // SDL_Delay (33);
            }
        }// end if
        // Free the packet that was allocated by av_read_frame
        av_free_packet (&packet);
    }// end while of reading one frame;
    
    // Free the RGB image
    av_free (pFrameYUV);
    // Free the YUV frame
    av_free (pFrame);
    // for test lsosa
    // printf("size = %d ", size / 1024 / 1024 );
    SDL_FreeYUVOverlay (overlay);
    
    close_file(fd);
}

void av_close (AVFormatContext * pFormatCtx, AVCodecContext * pAudioCodecCtx, 
    AVCodecContext * pVideoCodecCtx)
...{
    // close the file and codec
    // Close the codec
    avcodec_close (pAudioCodecCtx);
    // Close the codec
    avcodec_close (pVideoCodecCtx);

    // Close the video file
    av_close_input_file (pFormatCtx);
}

//------------------------------------------------------------------------------

int main (int argc, char **argv)...{
    //
    AVFormatContext *pFormatCtx;
    int audioStream = -1;
    int videoStream = -1;
    AVCodecContext *pAudioCodecCtx;
    AVCodecContext *pVideoCodecCtx;
    
    // exclude the error about args;
    if ( argc != 2 )...{
        printf("please give a file name ");
        exit(0);
    }
    
    // 注意:这里要用到指向指针的指针,是因为这个初始化函数需要对指针的地址进行改动,
    // 所以,只有这么做,才能达到目的;
    if ( av_init(argv[1], &pFormatCtx, &pAudioCodecCtx, &audioStream, &pVideoCodecCtx, &videoStream) < 0 )...{
        //
        fprintf(stderr, "error when av_init ");
    }
    
    // play the audio file
    av_play(pFormatCtx, pAudioCodecCtx, audioStream, pVideoCodecCtx, videoStream);
    
    // close all the opend files
    av_close(pFormatCtx, pAudioCodecCtx, pVideoCodecCtx);
    
}




分享到:
评论

相关推荐

    一个CD播放器源代码

    源代码中应包含音频解码模块,可能使用开源库如libcdio或ffmpeg。这部分代码会处理采样率转换、位深度转换和声道处理等任务,确保音频数据能在各种系统上正确播放。 3. **音频流处理**:解码后的音频数据需送入音频...

    mp3 小型 播放器 易语言 e语言 源码

    在本资源中,我们有一个使用易语言(e语言)编写的"mp3小型播放器"的源代码。这个播放器专为播放mp3格式的音频文件设计,对于学习易语言编程和音频处理的初学者来说,是一个非常有价值的实践项目。 首先,易语言的...

    QT:小型视频播放器,用于播放视频

    “video”可能是项目中的源代码或者资源文件夹,包含视频播放器所需的具体视频文件或相关配置。在这里,开发人员可能编写了处理视频流、控制播放、渲染视频帧以及响应用户交互的代码。QT的QVideoWidget或...

    ffmpeg0.6.1源码和在windows下编译出来的库

    在实际开发中,开发者可以使用这些库文件与应用程序链接,通过FFmpeg的API实现多媒体处理功能。例如,你可以加载一个视频文件,提取其音频流,对音频进行编码或解码,甚至进行实时的视频编码和流传输。 总结起来,...

    ffmpeg-tcc.zip

    不过,具体的功能和限制需要查看该版本的文档或源代码来了解。 总的来说,FFmpeg是一个功能强大的多媒体处理工具,其预编译版本的提供使得用户无需自己编译,节省了时间和资源,能够快速地在各种平台上应用FFmpeg...

    ASP.NET一个简单的媒体播放器的设计与实现(源代码+论文).rar

    在这个项目中,我们看到的是一个基于ASP.NET的简单媒体播放器的设计与实现,它提供了源代码和相关论文,非常适合用作毕业设计、课程设计或者自我提升的学习材料。 在ASP.NET中,这个媒体播放器可能使用C#作为后端...

    Playflv.rar

    标题“Playflv.rar”暗示这是一个包含C#源代码的压缩包,可能是一个小型项目或库,用于处理FLV视频播放功能。以下是对这个主题的详细讲解: 首先,FLV是一种流行的网络视频格式,广泛用于在线流媒体服务。由于它在...

    ffplay精简版VC6.0平台c源码

    ffplay 是 FFmpeg 项目中的一个小型命令行播放器,它用C语言编写,展示了如何直接使用FFmpeg库来实现基本的多媒体播放功能。在这个精简版中,开发者可能已经去除了不必要的功能,使其更易于理解和学习。主要包含以下...

    c语言做的播放器源码.rar

    "c语言做的播放器源码"很可能是实际的源代码文件,可能包含了播放器的主程序和其他相关的函数库、头文件等。 C语言制作的播放器通常会涉及到以下几个关键知识点: 1. **文件I/O**:播放器需要读取音频或视频文件,...

    media player

    在本文中,我们将深入探讨自制的小型音乐播放器的设计与实现,这是一款功能简单、代码精炼的工具,适合初学者学习编程和多媒体处理。 首先,我们来了解媒体播放器的基本功能。一个基本的音乐播放器通常包含以下组件...

    MinGW+msys编译环境

    MinGW是一个小型的GNU开发工具集,它包含了GCC(GNU Compiler Collection)和其他一些必要的库,如glibc和POSIX接口,允许开发者在Windows系统下使用GNU工具链来编译源代码。GCC支持多种编程语言,包括C、C++、...

    zplayer:在C#上创建的小型媒体播放器

    总结,"zplayer" 是一个使用 C# 开发的轻量级媒体播放器,其设计可能结合了 C# 的面向对象特性、.NET Framework 的资源,以及媒体处理的底层技术,如 DirectX 或 FFmpeg,为用户提供一个简洁易用的媒体播放体验。

    ffplay+activex+mfc+rtsp+vs2010

    项目中的 "FFMPEG_VideoOcx" 可能是开发过程中生成的 ActiveX 控件的编译结果或者源代码文件夹,包含了实现以上功能的具体代码。开发者可能使用了 FFmpeg 的 API 来集成解码和播放功能,同时利用 MFC 的类库来处理...

    All-code-linux-libraries.rar_linux libraries

    "All-code-linux-libraries.rar"这个压缩包似乎包含了Linux系统中广泛使用的各种库的源代码,这对于学习、理解和调试Linux程序是非常有价值的。 首先,我们要了解库的分类。在Linux中,主要有两种类型的库:静态库...

    嵌入式linux下的mplayer的移植

    在嵌入式Linux系统中,将MPlayer移植到设备上是一项关键任务,因为这使得用户能够在小型、低功耗的硬件上享受多媒体播放功能。MPlayer是一款强大的开源媒体播放器,支持多种视频和音频格式,它可以在各种操作系统上...

    lcd.rar_L2F50_generic_l2f50 library_libavcodec

    libavcodec是FFmpeg项目的一部分,是一个强大的多媒体处理库,主要用于视频和音频的编码和解码。通常,LCD驱动用于显示视频和图像,而libavcodec则负责处理这些媒体数据的编码和解码工作。将L2F50 LCD驱动与...

    MinGW,最新完整版MinGW

    GCC通过将源代码转换为机器码,使得程序能够在Windows平台上运行。 2. **MSYS**:这是一个小型的Unix-like环境,它为MinGW提供了命令行工具,如bash shell、make工具等,使用户可以使用类似Unix的命令行语法进行...

    数码相框源码

    开发者需要编写单元测试和集成测试,使用GDB等工具进行调试,确保代码的质量和性能。 通过深入理解这些知识点,开发者可以有效地修改、扩展和优化数码相框源码,以满足特定的需求和场景。无论是对个人项目还是商业...

    min

    1. **源码解析**:深入解析特定项目的源代码,包括代码结构、设计模式、编程技巧等,帮助读者理解并学习如何编写高效、可维护的代码。 2. **代码优化**:讲解如何通过改进代码结构、选择合适的算法、减少冗余操作等...

Global site tag (gtag.js) - Google Analytics