⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libav_decoder.cpp

📁 linux下实现视频播放的播放器
💻 CPP
字号:
/* *  Copyright (C) 2005-2007  gulikoza, mtrooper * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* $Id$ */#include "iptv.h"#define USES_BASECLASS#include "video.h"#include "wxgui/StreamInfo.h"#if (C_HAS_LIBAVCODEC)//#define DEBUG#include "log.h"#define MODULE "libav_decoder"/* Define to use direct buffer rendering */#define USE_DBRstatic enum PixelFormat GetFormat(AVCodecContext * s, const enum PixelFormat * fmt){    int i = -1;    do {	i++;	LOG_MSG("Codec offered format: %d", fmt[i]);    } while(fmt[i] != PIX_FMT_NONE);    return fmt[0];}static unsigned int pts = 0;static Renderer * renderer = NULL;static int GetBuffer(struct AVCodecContext *c, AVFrame *pic){    int w, h;    Frame frame;    w = frame.w = c->width; h = frame.h = c->height;    pic->pts = pts;    /* Some codecs set pix_fmt only after the 1st frame     * has been decoded, so this check is necessary. */#ifdef USE_DBR    if((renderer == NULL) || (c->pix_fmt == -1))#endif    {	pic->opaque = (void*)-1;	LOG_MSG("GetBuffer called, pts will be set to: %u, using internal buffer", pts);	return avcodec_default_get_buffer(c, pic);    }    avcodec_align_dimensions(c, &w, &h);    if(!(c->flags&CODEC_FLAG_EMU_EDGE)) {	w += 32; h += 32;	frame.edge = 16;    }    avcodec_align_dimensions(c, &w, &h);    frame.pitch = w;    renderer->LockData(&frame);    if(frame.id < 0) {	pic->opaque = (void*)-1;	LOG_MSG("GetBuffer called, pts will be set to: %u, using internal buffer", pts);	return avcodec_default_get_buffer(c, pic);    }    pic->opaque = (void*)frame.id;    LOG_MSG("GetBuffer called, pts will be set to: %u, picid: %d", pts, frame.id);    /* Who wrote a codec that writes *before* the address it has been passed?!? */    pic->data[0] = frame.data[0] +  (frame.edge * frame.pitch) + frame.edge;    pic->data[1] = frame.data[1] + ((frame.edge * frame.pitch)>>2) + (frame.edge>>1);    pic->data[2] = frame.data[2] + ((frame.edge * frame.pitch)>>2) + (frame.edge>>1);    pic->data[3] = NULL;    LOG_MSG("Buffers at %p %p %p", pic->data[0], pic->data[1], pic->data[2]);    pic->linesize[0] = frame.pitch;    pic->linesize[1] = frame.pitch>>1;    pic->linesize[2] = frame.pitch>>1;    pic->linesize[3] = 0;    pic->type = FF_BUFFER_TYPE_USER;    pic->age = 256*256*256*64;    return 0;}static void ReleaseBuffer(struct AVCodecContext *c, AVFrame *pic){    LOG_MSG("ReleaseBuffer called, picid: %p, data[0]: %p", pic->opaque, pic->data[0]);    if(pic->opaque == (void*)-1)	return avcodec_default_release_buffer(c, pic);    if(renderer) renderer->ReleaseData((int)PT2L(pic->opaque));    pic->data[0] = NULL;    pic->data[1] = NULL;    pic->data[2] = NULL;}static int ReGetBuffer(struct AVCodecContext *c, AVFrame *pic){    LOG_MSG("RegetBuffer called, picid: %p, data[0]: %p", pic->opaque, pic->data[0]);    if(pic->opaque == (void*)-1)	return avcodec_default_reget_buffer(c, pic);    if(pic->data[0] == NULL)	return GetBuffer(c, pic);    return 0;}int libav_decoder::Run(){    AVCodec *codec;    AVCodecContext *c = NULL;    AVFrame *picture;    // Pitcure info    int w = 0, h = 0;    int got_picture, len;#if (C_HAVE_WXGUI)    long frameSize;    Uint32 frameStartTicks;#endif    // Init libavcodec decoder    avcodec_init();    avcodec_register_all();    codec = avcodec_find_decoder(codecID);    if(!codec) {	ERROR_MSG("Unable to find a suitable codec!");	return 0;    }    c = avcodec_alloc_context();    picture = avcodec_alloc_frame();    if(avcodec_open(c, codec) < 0) {	ERROR_MSG("Unable to open codec");	return 0;    }    // Init codec    c->opaque = codec;    // Set optimal idct algorithm?    // Callback for pixel format    c->get_format = GetFormat;    // Custom get_buffer callback    c->get_buffer = GetBuffer;    c->reget_buffer = ReGetBuffer;    c->release_buffer = ReleaseBuffer;    ERROR_MSG("(ThreadID: %u) init complete", SDL_ThreadID());#ifdef DEBUG    // Frame counter, only for reference    int frames = 0;#endif    // Target surface info    Frame frame;#if (C_HAVE_WXGUI)    frameSize = 0;    frameStartTicks = SDL_GetTicks();#endif    while(ThreadRun()) {	renderer = (Renderer*)filterinfo;	// Get next packet from the fifo queue	unsigned int offset, m_size;	m_size = fifo->GetPacket(&offset, &pts);#if (C_HAVE_WXGUI)	frameSize += m_size;#endif	if((m_size == 0) || (m_size > buffersize)) {	    LOG_MSG("Error invalid packet size: %d", m_size);	    SDL_Delay(10);	    continue;	}	LockBuffer();	roffset = offset;	if(!SDL_SemValue(data))	    SDL_SemPost(data);	UnlockBuffer();	len = avcodec_decode_video(c, picture, &got_picture, buffer+offset, m_size);	if(len < 0) {	    LOG_MSG("Error while decoding frame (%d bytes dropped)", m_size);	    continue;	}	if((got_picture) && (renderer)) {	    frame.time = av_q2d(c->time_base) * 1000;	    frame.pts = picture->pts;	    LOG_MSG("Frame period set to %.2f, pts %u", frame.time, frame.pts);	    // Check for video size change	    if((w != c->width) || (h != c->height)) {		w = c->width;		h = c->height;		LOG_MSG("New picture size: %dx%d, AR: %.2f", w, h, av_q2d(c->sample_aspect_ratio));		frame.changed = true;	    }	    if(frame.aspect != ((w&0xFFFFFFE0) * av_q2d(c->sample_aspect_ratio)) / h) {		frame.aspect = ((w&0xFFFFFFE0) * av_q2d(c->sample_aspect_ratio)) / h;		frame.changed = true;	    }#if (C_HAVE_WXGUI)	    // New frame size	    if((frame.changed) && (gui.wxStreamInfo != NULL)) {		gui.wxStreamInfo->UpdateVideoStream(w, h, c->bit_rate, frame.aspect);		frameSize = 0;		frameStartTicks = SDL_GetTicks();	    }#endif	    // Picture is in internal buffers	    if(picture->opaque == (void*)-1) {		frame.pitch = frame.w = w; frame.h = h;		renderer->LockData(&frame);		if(frame.id < 0) continue;		LOG_MSG("Copying from internal buffers: %dx%d", picture->linesize[0], h);		unsigned char * src[3], * dst[3];		src[2] = picture->data[0];		src[0] = picture->data[1];		src[1] = picture->data[2];		dst[2] = frame.data[0];		dst[0] = frame.data[1];		dst[1] = frame.data[2];		register int j = h;		register int k = 0;		while(j--) {		    // Y		    SDL_memcpy(dst[2], src[2], w); dst[2] += w; src[2] += picture->linesize[0];		    // U & V		    SDL_memcpy(dst[k], src[k], w>>1); dst[k] += w>>1; src[k] += picture->linesize[1];		    k = (k+1)&1;		}	    } else {		frame.id = (int)PT2L(picture->opaque);	    }	    // Unlock target surface	    renderer->UnlockData(frame.id, &frame);	    frame.changed = false;#if (C_HAVE_WXGUI)	    Uint32 frameTimeTaken = SDL_GetTicks() - frameStartTicks;	    // Update ~twice per second	    if(frameTimeTaken > 500) {		if(gui.wxStreamInfo != NULL)		    gui.wxStreamInfo->UpdateVideoActualBitrate((long)((double)frameSize * 8000.0 / (double)frameTimeTaken));		frameSize = 0;		frameStartTicks = SDL_GetTicks();	    }#endif#ifdef DEBUG	    ++frames;#endif	}    }    if(renderer)	renderer->FlushBuffers();    avcodec_close(c);    av_free(c);    av_free(picture);    ERROR_MSG("(ThreadID: %u) finish complete", SDL_ThreadID());    return 0;}#endif // (C_HAS_LIBAVCODEC)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -