void RenderThread::RenderFrames(FrameListPtr sourceFrames, YUV_PLANE plane) { FrameImpl tempFrame; for (int i = 0; i < sourceFrames->size(); i++) { FramePtr sourceFrameOrig = sourceFrames->at(i); if (!sourceFrameOrig) { continue; } unsigned int viewID = sourceFrameOrig->Info(VIEW_ID).toUInt(); Frame* sourceFrame = sourceFrameOrig.data(); float scaleX = 1; float scaleY = 1; if (plane != PLANE_COLOR) { COLOR_FORMAT c = sourceFrameOrig->Format()->Color(); if (c == I420 || c == I422 || c == I444) { sourceFrame = &tempFrame; FormatPtr format = sourceFrameOrig->Format(); sourceFrame->Format()->SetColor(Y800); sourceFrame->Format()->SetWidth(format->PlaneWidth(plane)); sourceFrame->Format()->SetHeight(format->PlaneHeight(plane)); sourceFrame->Format()->SetStride(0, format->Stride(plane)); sourceFrame->Format()->PlaneSize(0); sourceFrame->SetData(0, sourceFrameOrig->Data(plane)); scaleX = ((float)format->PlaneWidth(plane))/format->Width(); scaleY = ((float)format->PlaneHeight(plane))/format->Height(); } } int pos = -1; for (int k = 0; k < m_RenderFrames.size(); k++) { FramePtr _frame = m_RenderFrames.at(k); if (_frame && _frame->Info(VIEW_ID).toUInt() == viewID) { pos = k; break; } } if (pos == -1) { pos = m_RenderFrames.size(); m_RenderFrames.append(FramePtr()); } FramePtr& renderFrame = m_RenderFrames[pos]; // Deallocate if resolution changed if (renderFrame && (sourceFrame->Format()->Width() != renderFrame->Format()->Width() || sourceFrame->Format()->Height() != renderFrame->Format()->Height())) { m_Renderer->Deallocate(renderFrame); renderFrame.clear(); } // Allocate if needed if (!renderFrame) { m_Renderer->Allocate(renderFrame, sourceFrame->Format()); } renderFrame->SetInfo(VIEW_ID, viewID); renderFrame->SetInfo(RENDER_SRC_SCALE_X, scaleX); renderFrame->SetInfo(RENDER_SRC_SCALE_Y, scaleY); // Render frame if (m_Renderer->GetFrame(renderFrame) == OK) { if (sourceFrame->Format() == renderFrame->Format()) { for (int i=0; i<4; i++) { size_t len = renderFrame->Format()->PlaneSize(i); if (len > 0) { memcpy(renderFrame->Data(i), sourceFrame->Data(i), len); } } }else { ColorConversion(*sourceFrame, *renderFrame); } m_Renderer->ReleaseFrame(renderFrame); } } }
void MotionCompensator::CompensateComponent(Frame& picframe, const Frame &ref1frame, const Frame& ref2frame, const MvData& mv_data,const CompSort cs) { // Set up references to pictures and references PicArray& pic_data_out = picframe.Data( cs ); const PicArray& ref1up = ref1frame.UpData( cs ); const PicArray& ref2up = ref2frame.UpData( cs ); // Set up another picture which will contain the MC data, which // we'll add or subtract to pic_data_out TwoDArray<CalcValueType> pic_data(pic_data_out.LengthY(), pic_data_out.LengthX() , 0); // Factors to compensate for subsampling of chroma int xscale_factor = 1; int yscale_factor = 1; if ( cs != Y_COMP ) { if (m_cformat == format420) { xscale_factor = 2; yscale_factor = 2; } else if (m_cformat == format422) { xscale_factor = 2; yscale_factor = 1; } else if (m_cformat == format411) { xscale_factor = 4; yscale_factor = 1; } } // Reference to the relevant DC array const TwoDArray<ValueType>& dcarray = mv_data.DC( cs ); // Set up references to the vectors const int num_refs = picframe.GetFparams().Refs().size(); const MvArray* mv_array1; const MvArray* mv_array2; mv_array1 = &mv_data.Vectors(1); if (num_refs ==2 ) mv_array2 = &mv_data.Vectors(2); else mv_array2 = &mv_data.Vectors(1); ReConfig();//set all the weighting blocks up //Blocks are listed left to right, line by line. MVector mv1,mv2; PredMode block_mode; ValueType dc; //Coords of the top-left corner of a block ImageCoords pos; //Loop for each block in the output image. //The CompensateBlock function will use the image pointed to by ref1up //and add the compensated pixels to the image pointed to by pic_data. size_t wgt_idx; //Loop over all the block rows pos.y = -m_bparams.Yoffset(); for(int yblock = 0; yblock < m_cparams.YNumBlocks(); ++yblock) { pos.x = -m_bparams.Xoffset(); //loop over all the blocks in a row for(int xblock = 0 ; xblock < m_cparams.XNumBlocks(); ++xblock) { //Decide which weights to use. if((xblock != 0)&&(xblock < m_cparams.XNumBlocks() - 1)) { if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1)) wgt_idx = 4; else if(yblock == 0) wgt_idx = 1; else wgt_idx= 7; } else if(xblock == 0) { if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1)) wgt_idx = 3; else if(yblock == 0) wgt_idx = 0; else wgt_idx = 6; } else { if((yblock != 0)&&(yblock < m_cparams.YNumBlocks() - 1)) wgt_idx = 5; else if(yblock == 0) wgt_idx = 2; else wgt_idx = 8; } block_mode = mv_data.Mode()[yblock][xblock]; mv1 = (*mv_array1)[yblock][xblock]; mv1.x /= xscale_factor; mv1.y /= yscale_factor; mv2 = (*mv_array2)[yblock][xblock]; mv2.x /= xscale_factor; mv2.y /= yscale_factor; dc = dcarray[yblock][xblock]<<2;// DC is only given 8 bits, // so need to shift to get 10-bit data if(block_mode == REF1_ONLY) { CompensateBlock(pic_data, ref1up, mv1, pos, m_block_weights[wgt_idx]); } else if (block_mode == REF2_ONLY) { CompensateBlock(pic_data, ref2up, mv2, pos, m_block_weights[wgt_idx]); } else if(block_mode == REF1AND2) { CompensateBlock(pic_data, ref1up, mv1, pos, m_half_block_weights[wgt_idx]); CompensateBlock(pic_data, ref2up, mv2, pos, m_half_block_weights[wgt_idx]); } else {//we have a DC block. DCBlock(pic_data, dc,pos, m_block_weights[wgt_idx]); } //Increment the block horizontal position pos.x += m_bparams.Xbsep(); }//xblock //Increment the block vertical position pos.y += m_bparams.Ybsep(); }//yblock if ( m_add_or_sub == SUBTRACT) { int x_end_data = std::min(pic_data.LastX(), m_cparams.XNumBlocks()*m_bparams.Xbsep() ); int y_end_data = std::min(pic_data.LastY(), m_cparams.YNumBlocks()*m_bparams.Ybsep() ); for ( int i =pic_data.FirstY(); i <= y_end_data; i++) { for ( int j =pic_data.FirstX(); j <= x_end_data; ++j) { pic_data_out[i][j] -= static_cast<ValueType>( (pic_data[i][j] + 1024) >> 11 ); } // Okay, we've done all the actual blocks. Now if the picture is further padded // we need to set the padded values to zero beyond the last block in the row, // for all the picture lines in the block row. Need only do this when we're // subtracting. for (int j=( m_cparams.XNumBlocks()*m_bparams.Xbsep() ); j<pic_data.LengthX() ; ++j ) { pic_data_out[i][j] = 0; } } // Finally, now we've done all the blocks, we must set all padded lines below // the last row equal to 0, if we're subtracting for ( int y=m_cparams.YNumBlocks()*m_bparams.Ybsep() ; y<pic_data.LengthY() ; ++y ) { for ( int x=0 ; x<pic_data.LengthX() ; ++x ) { pic_data_out[y][x] = 0; } } }
void MotionCompensator::CompensateComponent( Frame& picframe , const Frame &ref1frame , const Frame& ref2frame , const MvData& mv_data , const CompSort cs) { // Set up references to pictures and references PicArray& pic_data_out = picframe.Data( cs ); // Size of frame component being motion compensated const PicArray& ref1up = ref1frame.UpData( cs ); const PicArray& ref2up = ref2frame.UpData( cs ); // Set up a row of blocks which will contain the MC data, which // we'll add or subtract to pic_data_out TwoDArray<ValueType> pic_data(m_bparams.Yblen(), pic_data_out.LengthX(), 0 ); // Factors to compensate for subsampling of chroma int xscale_shift = 0; int yscale_shift = 0; if ( cs != Y_COMP ) { if (m_cformat == format420) { xscale_shift = 1; yscale_shift = 1; } else if (m_cformat == format422) { xscale_shift = 1; yscale_shift = 0; } } ImageCoords orig_pic_size(picframe.GetFparams().OrigXl(), picframe.GetFparams().OrigYl()); if ( cs != Y_COMP ) { orig_pic_size.x = picframe.GetFparams().OrigChromaXl(); orig_pic_size.y = picframe.GetFparams().OrigChromaYl(); } // Reference to the relevant DC array const TwoDArray<ValueType>& dcarray = mv_data.DC( cs ); // Set up references to the vectors const int num_refs = picframe.GetFparams().Refs().size(); const MvArray* mv_array1; const MvArray* mv_array2; mv_array1 = &mv_data.Vectors(1); if (num_refs ==2 ) mv_array2 = &mv_data.Vectors(2); else mv_array2 = &mv_data.Vectors(1); ReConfig();//set all the weighting blocks up //Blocks are listed left to right, line by line. MVector mv1,mv2; PredMode block_mode; //Coords of the top-left corner of a block ImageCoords pos; //Loop for each block in the output image. //The CompensateBlock function will use the image pointed to by ref1up //and add the compensated pixels to the image pointed to by pic_data. size_t wgt_idx; int save_from_row = m_bparams.Ybsep()-m_bparams.Yoffset(); // unpadded picture dimensions const int x_end_data = pic_data_out.FirstX() + std::min(pic_data_out.LengthX(), orig_pic_size.x ); const int y_end_data = pic_data_out.FirstY() + std::min(pic_data_out.LengthY(), orig_pic_size.y ); const int blocks_per_mb_row = m_cparams.XNumBlocks()/m_cparams.XNumMB(); const int blocks_per_sb_row = blocks_per_mb_row>>1; // The picture does not contain integral number of blocks. So not all // blocks need to be processed. Compute the relevant blocks to be // processed using the original picturesize and not the padded pic size int y_num_blocks = NUM_USED_BLKS(orig_pic_size.y,m_bparams.Ybsep(),m_bparams.Yblen()); int x_num_blocks = NUM_USED_BLKS(orig_pic_size.x,m_bparams.Xbsep(),m_bparams.Xblen()); //Loop over all the block rows pos.y = -m_bparams.Yoffset(); for(int yblock = 0; yblock < y_num_blocks; ++yblock) { pos.x = -m_bparams.Xoffset(); int xincr, xb_incr = 0; //loop over all the blocks in a row for(int xblock = 0 ; xblock < x_num_blocks; xblock+=xb_incr) { int split_mode = mv_data.MBSplit()[yblock/blocks_per_mb_row][xblock/blocks_per_mb_row]; int blk_len_x, blk_len_y = m_bparams.Yblen(); switch (split_mode) { case 0: // processing superblock blk_len_x = blocks_per_mb_row * m_bparams.Xblen(); break; case 1: // processing sub-superblock blk_len_x = blocks_per_sb_row * m_bparams.Xblen(); break; case 2: // processing block default: blk_len_x = m_bparams.Xblen(); break; } //Decide which weights to use. if (pos.x >=0 && (pos.x+blk_len_x) < orig_pic_size.x) { // block is entirely within picture in x direction if (pos.y < 0) wgt_idx = 1; else if ((pos.y+blk_len_y) < orig_pic_size.y) wgt_idx = 4; else wgt_idx = 7; } else if (pos.x < 0) { // left edge of block is outside picture in x direction if (pos.y < 0) wgt_idx = 0; else if ((pos.y+blk_len_y) < orig_pic_size.y) wgt_idx = 3; else wgt_idx = 6; } else { // right edge of block is outside picture in x direction if (pos.y < 0) wgt_idx = 2; else if ((pos.y+blk_len_y) < orig_pic_size.y) wgt_idx = 5; else wgt_idx = 8; } block_mode = mv_data.Mode()[yblock][xblock]; TwoDArray<ValueType> *wt; if (split_mode == 0) //Block part of a MacroBlock { wt = &m_macro_block_weights[wgt_idx]; xb_incr = blocks_per_mb_row; } else if (split_mode == 1) //Block part of a SubBlock { wt = &m_sub_block_weights[wgt_idx]; xb_incr = blocks_per_sb_row; } else { wt = &m_block_weights[wgt_idx]; xb_incr = 1; } xincr = m_bparams.Xbsep() * xb_incr; mv1 = (*mv_array1)[yblock][xblock]; mv1.x >>= xscale_shift; mv1.y >>= yscale_shift; mv2 = (*mv_array2)[yblock][xblock]; mv2.x >>= xscale_shift; mv2.y >>= yscale_shift; CompensateBlock(pic_data, pos, orig_pic_size, block_mode, dcarray[yblock][xblock], ref1up, mv1, ref2up, mv2, *wt); //Increment the block horizontal position pos.x += xincr; }//xblock // Update the pic data // Use only the first Ybsep rows since the remaining rows are // needed for the next row of blocks since we are using overlapped // blocks motion compensation if (m_add_or_sub == SUBTRACT) { int start_y = std::max(pic_data_out.FirstY() , pos.y) ; int end_y = std::min (pic_data_out.FirstY() + pos.y + m_bparams.Ybsep() , y_end_data); if (yblock == y_num_blocks - 1) { end_y = pic_data_out.LengthY(); if (end_y > y_end_data) end_y = y_end_data; } for ( int i = start_y, pos_y = 0; i < end_y; i++, pos_y++) { ValueType *pic_row = pic_data[pos_y]; ValueType *out_row = pic_data_out[i]; for ( int j =pic_data_out.FirstX(); j < x_end_data; ++j) { out_row[j] -= static_cast<ValueType>( (pic_row[j] + 32) >> 6 ); } // Okay, we've done all the actual blocks. Now if the picture is further padded // we need to set the padded values to zero beyond the last block in the row, // for all the picture lines in the block row. Need only do this when we're // subtracting. for (int j=orig_pic_size.x; j<pic_data_out.LengthX() ; ++j ) { out_row[pic_data_out.FirstX()+j] = 0; } } } else // (m_add_or_sub == ADD) {
void ColorConversion(const Frame& in, Frame& out) { const FormatPtr format_in = in.Format(); FormatPtr format_out = out.Format(); int step_in[4]; memcpy(step_in, format_in->Stride(), sizeof(step_in)); unsigned char* data_in[4], *data_out[4]; memcpy(data_in, in.Data(), sizeof(data_in)); memcpy(data_out, out.Data(), sizeof(data_out)); COLOR_FORMAT color_in = format_in->Color(); COLOR_FORMAT color_out = format_out->Color(); if (color_in == IMC2) { color_in = YV12; data_in[2] = data_in[1]+format_in->Width()/2; step_in[2] = step_in[1]; }else if (color_in == IMC4) { color_in = I420; data_in[2] = data_in[1]+format_in->Width()/2; step_in[2] = step_in[1]; }else if (color_in == YVYU) { // Special case since ffmpeg converter doesn't have this by default // Swap chroma plans data_out[3] = data_out[1]; data_out[1] = data_out[2]; data_out[2] = data_out[3]; data_out[3] = 0; } PrepareCC(color_in, data_in); PrepareCC(color_out, data_out); bool ok = false; if (!ok) { // Try FFMpeg conversion if framewave doesn't support the conversion struct SwsContext *ctx = sws_getContext(format_in->Width(), format_in->Height(), YT2FFMpegFormat(color_in), format_out->Width(), format_out->Height(), YT2FFMpegFormat(color_out), SWS_BILINEAR, NULL,NULL,NULL ); if (ctx) { if (sws_scale( ctx, data_in, step_in, 0, format_in->Height(), data_out, format_out->Stride()) == format_out->Height()) { ok = true; } sws_freeContext( ctx ); } } if (!ok) { // Fill with random data for (int i=0; i<4; i++) { for (int j=0; j<format_out->Stride(i)*format_out->Height(); j++) { data_out[i][j] = rand()*255/RAND_MAX; } } } out.SetPTS(in.PTS()); out.SetFrameNumber(in.FrameNumber()); for (int i=0; i<LAST_INFO_KEY; i++) { if (in.HasInfo((INFO_KEY)i)) { out.SetInfo((INFO_KEY)i, in.Info((INFO_KEY)i)); } } }