nengel@2: /* nengel@2: * H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder nengel@2: * Copyright (c) 2003 Michael Niedermayer nengel@2: * nengel@2: * This file is part of FFmpeg. nengel@2: * nengel@2: * FFmpeg is free software; you can redistribute it and/or nengel@2: * modify it under the terms of the GNU Lesser General Public nengel@2: * License as published by the Free Software Foundation; either nengel@2: * version 2.1 of the License, or (at your option) any later version. nengel@2: * nengel@2: * FFmpeg is distributed in the hope that it will be useful, nengel@2: * but WITHOUT ANY WARRANTY; without even the implied warranty of nengel@2: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU nengel@2: * Lesser General Public License for more details. nengel@2: * nengel@2: * You should have received a copy of the GNU Lesser General Public nengel@2: * License along with FFmpeg; if not, write to the Free Software nengel@2: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA nengel@2: */ nengel@2: #include "h264_types.h" nengel@2: #include "h264_parser.h" nengel@2: #include "h264_nal.h" nengel@2: #include "h264_entropy.h" nengel@2: #include "h264_rec.h" nengel@2: #include "h264_pred_mode.h" nengel@2: #include "h264_misc.h" nengel@2: // #undef NDEBUG nengel@2: #include nengel@2: nengel@2: static int decode_slice_entropy_seq(H264Context *h, EntropyContext *ec, H264Slice *s, GetBitContext *gb, H264Mb *mbs){ nengel@2: int i,j; nengel@2: // GetBitContext *gb = s->gb; nengel@2: CABACContext *c = &ec->c; nengel@2: nengel@2: if( !s->pps.cabac ){ nengel@2: av_log(AV_LOG_ERROR, "Only cabac encoded streams are supported\n"); nengel@2: return -1; nengel@2: } nengel@2: nengel@2: init_dequant_tables(s, ec); nengel@2: ec->curr_qscale = s->qscale; nengel@2: ec->last_qscale_diff = 0; nengel@2: ec->chroma_qp[0] = get_chroma_qp((H264Slice *) s, 0, s->qscale); nengel@2: ec->chroma_qp[1] = get_chroma_qp((H264Slice *) s, 1, s->qscale); nengel@2: nengel@2: /* realign */ nengel@2: align_get_bits( gb ); nengel@2: /* init cabac */ nengel@2: ff_init_cabac_decoder( c, gb->buffer + get_bits_count(gb)/8, (get_bits_left(gb) + 7)/8); nengel@2: nengel@2: ff_h264_init_cabac_states(ec, s, c); nengel@2: nengel@2: for(j=0; jmb_height; j++){ nengel@2: init_entropy_buf(ec, s, j); nengel@2: for(i=0; imb_width; i++){ nengel@2: int eos,ret; nengel@2: H264Mb *m = &mbs[i + j*ec->mb_width]; nengel@2: //memset(m, 0, sizeof(H264Mb)); nengel@2: m->mb_x=i; nengel@2: m->mb_y=j; nengel@2: ec->m = m; nengel@2: nengel@2: ret = ff_h264_decode_mb_cabac(ec, s, c); nengel@2: eos = get_cabac_terminate( c); nengel@2: (void) eos; nengel@2: if( ret < 0 || c->bytestream > c->bytestream_end + 2) { nengel@2: av_log(AV_LOG_ERROR, "error while decoding MB %d %d, bytestream (%td)\n", m->mb_x, m->mb_y, c->bytestream_end - c->bytestream); nengel@2: return -1; nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: // av_freep(&s->gb.raw); nengel@2: // if (s->gb.rbsp) nengel@2: // av_freep(&s->gb.rbsp); nengel@2: nengel@2: return 0; nengel@2: } nengel@2: nengel@2: nengel@2: nengel@2: /** nengel@2: * Sequential version nengel@2: */ nengel@2: static void decode_slice_mb_seq(H264Context *h, MBRecContext *d, H264Slice *s2, H264Mb *mbs){ nengel@2: nengel@2: for (int i=0; i<2; i++){ nengel@2: for(int j=0; j< s2->ref_count[i]; j++){ nengel@2: if (s2->ref_list_cpn[i][j] ==-1) nengel@2: continue; nengel@2: int k; nengel@2: for (k=0; kmax_dpb_cnt; k++){ nengel@2: if(h->dpb[k].reference >= 2 && h->dpb[k].cpn == s2->ref_list_cpn[i][j]){ nengel@2: s2->dp_ref_list[i][j] = &h->dpb[k]; nengel@2: break; nengel@2: } nengel@2: } nengel@2: } nengel@2: } nengel@2: nengel@2: get_dpb_entry(h, s2); nengel@2: nengel@2: if (!h->no_mbd){ nengel@2: for(int j=0; jmb_height; j++){ nengel@2: init_mbrec_context(d, d->mrs, s2, j); nengel@2: if (h->profile) printf("\n[MBREC LINE %d ", j); nengel@2: for(int i=0; imb_width; i++){ nengel@2: nengel@2: if ((i & 0x7) == 0) start_timer(h, REC); nengel@2: H264Mb *m = &mbs[i + j*d->mb_width]; nengel@2: if (h->profile==2) nengel@2: pred_motion_mb_rec (d, d->mrs, s2, m); nengel@2: else{ nengel@2: h264_decode_mb_internal(d, d->mrs, s2, m); nengel@2: } nengel@2: stop_timer(h, REC); nengel@2: } nengel@2: draw_edges(d, s2, j); nengel@2: nengel@2: } nengel@2: } nengel@2: nengel@2: for (int i=0; irelease_cnt; i++){ nengel@2: for(int j=0; jmax_dpb_cnt; j++){ nengel@2: if(h->dpb[j].cpn== s2->release_ref_cpn[i]){ nengel@2: release_dpb_entry(h, &h->dpb[j], 2); nengel@2: break; nengel@2: } nengel@2: } nengel@2: } nengel@2: s2->release_cnt=0; nengel@2: } nengel@2: nengel@2: /* nengel@2: * The following code is the main loop of the file converter nengel@2: */ nengel@2: int h264_decode_seq( H264Context *h) { nengel@2: ParserContext *pc; nengel@2: NalContext *nc; nengel@2: EntropyContext *ec; nengel@2: MBRecContext *rc; nengel@2: OutputContext *oc; nengel@2: nengel@2: H264Slice slice, *s=&slice; nengel@2: H264Mb *mbs; nengel@2: DecodedPicture *out; nengel@2: int frames=0; nengel@2: nengel@2: #if HAVE_LIBSDL2 nengel@2: pthread_t sdl_thr; nengel@2: if (h->display){ nengel@2: pthread_create(&sdl_thr, NULL, sdl_thread, h); nengel@2: } nengel@2: #endif nengel@2: nengel@2: pc = get_parse_context(h->ifile); nengel@2: nc = get_nal_context(h->width, h->height); nengel@2: nengel@2: memset(s, 0, sizeof(H264Slice)); nengel@2: mbs = av_malloc( h->mb_height * h->mb_width * sizeof(H264Mb)); nengel@2: nengel@2: ec = get_entropy_context( h ); nengel@2: rc = get_mbrec_context(h); nengel@2: rc->top_next = rc->top = av_malloc( h->mb_width * sizeof(TopBorder)); nengel@2: nengel@2: oc = get_output_context( h ); nengel@2: nengel@2: av_start_timer(); nengel@2: GetBitContext gb = {0,}; nengel@2: while(!pc->final_frame && frames++ < h->num_frames && !h->quit){ nengel@2: if (h->profile) start_timer(h, FRONT); nengel@2: av_read_frame_internal(pc, &gb); nengel@2: decode_nal_units(nc, s, &gb); nengel@2: if (h->profile) stop_timer(h, FRONT); nengel@2: // memset(s->mbs, 0, sizeof(H264Mb)*ec->mb_width*ec->mb_height); nengel@2: if (h->profile) start_timer(h, ED); nengel@2: decode_slice_entropy_seq(h, ec, s, &gb, mbs); nengel@2: if (h->profile) stop_timer(h, ED); nengel@2: nengel@2: if (h->profile) start_timer(h, REC); nengel@2: decode_slice_mb_seq(h, rc, s, mbs); nengel@2: if (h->profile) stop_timer(h, REC); nengel@2: nengel@2: out =output_frame(h, oc, s->curr_pic, h->ofile, h->frame_width, h->frame_height); nengel@2: if (out){ nengel@2: release_dpb_entry(h, out, 1); nengel@2: } nengel@2: nengel@2: print_report(oc->frame_number, oc->video_size, 0, h->verbose); nengel@2: if (h->profile == 3){ nengel@2: printf("[ENTROPY %.3fms] [MBREC %.3fms]\n", h->last_time[ED] , h->last_time[REC]); nengel@2: } nengel@2: } nengel@2: while ((out=output_frame(h, oc, NULL, h->ofile, h->frame_width, h->frame_height))) ; nengel@2: nengel@2: print_report(oc->frame_number, oc->video_size, 1, h->verbose); nengel@2: h->num_frames = oc->frame_number; nengel@2: /* finished ! */ nengel@2: av_freep(&mbs); nengel@2: av_freep(&gb.raw); nengel@2: if (gb.rbsp) nengel@2: av_freep(&gb.rbsp); nengel@2: av_freep(&rc->top); nengel@2: nengel@2: free_parse_context(pc); nengel@2: free_nal_context (nc); nengel@2: free_entropy_context(ec); nengel@2: free_mbrec_context(rc); nengel@2: free_output_context(oc); nengel@2: nengel@2: #if HAVE_LIBSDL2 nengel@2: if (h->display){ nengel@2: signal_sdl_exit(h); nengel@2: pthread_join(sdl_thr, NULL); nengel@2: } nengel@2: #endif nengel@2: nengel@2: return 0; nengel@2: }