?? libav_decoder.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)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -